gpt4 book ai didi

scala - 在解释器中使用 monad 有什么意义?

转载 作者:行者123 更新时间:2023-12-04 02:54:28 26 4
gpt4 key购买 nike

我最近发现了这个小scala example使用单子(monad)称为简单解释器:

object simpleInterpreter {

case class M[A](value: A) {
def bind[B](k: A => M[B]): M[B] = k(value)
def map[B](f: A => B): M[B] = bind(x => unitM(f(x)))
def flatMap[B](f: A => M[B]): M[B] = bind(f)
}

def unitM[A](a: A): M[A] = M(a)

def showM(m: M[Value]): String = m.value.toString();

type Name = String

trait Term;
case class Var(x: Name) extends Term
case class Con(n: int) extends Term
case class Add(l: Term, r: Term) extends Term
case class Lam(x: Name, body: Term) extends Term
case class App(fun: Term, arg: Term) extends Term

trait Value
case object Wrong extends Value {
override def toString() = "wrong"
}
case class Num(n: int) extends Value {
override def toString() = n.toString()
}
case class Fun(f: Value => M[Value]) extends Value {
override def toString() = "<function>"
}

type Environment = List[Pair[Name, Value]]

def lookup(x: Name, e: Environment): M[Value] = e match {
case List() => unitM(Wrong)
case Pair(y, b) :: e1 => if (x == y) unitM(b) else lookup(x, e1)
}

def add(a: Value, b: Value): M[Value] = Pair(a, b) match {
case Pair(Num(m), Num(n)) => unitM(Num(m + n))
case _ => unitM(Wrong)
}

def apply(a: Value, b: Value): M[Value] = a match {
case Fun(k) => k(b)
case _ => unitM(Wrong)
}

def interp(t: Term, e: Environment): M[Value] = t match {
case Var(x) => lookup(x, e)
case Con(n) => unitM(Num(n))
case Add(l, r) => for (val a <- interp(l, e);
val b <- interp(r, e);
val c <- add(a, b))
yield c
case Lam(x, t) => unitM(Fun(a => interp(t, Pair(x, a) :: e)))
case App(f, t) => for (val a <- interp(f, e);
val b <- interp(t, e);
val c <- apply(a, b))
yield c
}

def test(t: Term): String =
showM(interp(t, List()))

val term0 = App(Lam("x", Add(Var("x"), Var("x"))), Add(Con(10), Con(11)))
val term1 = App(Con(1), Con(2))

def main(args: Array[String]) {
println(test(term0))
println(test(term1))
}
}

这里一元计算的用途/优势是什么?事实上, M只不过是一个身份单子(monad)。这只是为了给出一个单子(monad)语法的例子还是它有重要的影响?

最佳答案

下面是对 Phil Wadler 论文的一点总结:
当您以直截了当的“直接”风格编写解释器时,在添加新功能时必须更改大量代码。例如,如果您添加异常,则必须检查是否在您可能评估表达式的任何地方引发异常,即使结构类似于 。如果 或函数调用,因此与异常无关。

如果您以 monadic 风格编写解释器,则只需更改 monad 即可添加新功能。您通常还会添加一些新的语法来支持该功能,但其余代码都没有更改。因此,monadic 风格是一种制作解释器的方式,该解释器在语言变化方面是模块化的。

例子:

  • 要添加异常,请将 monad 更改为 error monad,为 throw 添加新语法和代码和 catch ,并且您的其他代码都没有更改。
  • 要更改语言以使表达式的值是概率分布,而不仅仅是一个值,请更改 monad,并添加一个概率构造,例如“翻转有偏见的硬币”。同样,没有任何旧代码更改。 (这个真的很有趣;我有 done it myself 。)

  • 既然我已经告诉你一元计算的优点,我最好告诉你最大的缺点: 你一次只能做一个有趣的功能 .原因是一般来说,你不能组合两个 monad 来创建一个新的 monad。这不仅适用于一般情况,而且适用于您可能真正喜欢使用的 monad。

    如果您真的对制作模块化解释器感兴趣,您可以在其中轻松尝试不同的语言功能组合(而不仅仅是单个功能),您需要 monad 变压器 . Monad Transformers and Modular Interpreters 上有一篇很棒的论文盛亮、保罗·胡达克和马克·琼斯。这是一本很棒的书;我强烈推荐它。

    关于scala - 在解释器中使用 monad 有什么意义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1969254/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com