【发布时间】:2017-04-10 03:53:38
【问题描述】:
因为我定义了一个有很多变量的解释器,所以我写这个:
type Context = Map[String, Int]
abstract class Expr
case class Let(varname: String, varvalue: Expr, body: Expr) extends Expr
case class Var(name: String) extends Expr
case class Plus(a: Expr, b: Expr) extends Expr
case class Num(i: Int) extends Expr
def eval(expr: Expr)(implicit ctx: Context): Int = expr match {
case Let(i, e, b) => eval(b)(ctx + (i -> eval(e)))
case Var(s) => ctx(s)
case Num(i) => i
case Plus(a, b) => eval(a) + eval(b)
}
对于很长的表达式,由于StackOverflowException,这会失败,对于以下类型的表达式:
Let("a", 1,
Let("b", Plus("a", "a"),
Let("c", Plus("b", "a"),
Let("d", 1, ... )
但是,一旦定义了变量的值,我只需要在 Let 的主体上再次调用评估器,在我看来它应该只是进行某种部分尾递归。
Scala 中如何实现部分尾递归?
【问题讨论】:
-
像
eval(a)+eval(b)这样的表达式不会阻止尾递归吗?必须维护堆栈,以便在eval(a)完成后评估eval(b)?只有当返回值是对递归函数的单次调用时,尾递归才可能。 -
显然。这就是为什么我不能进行尾递归。但是,看,在我只有很多
Lets 的情况下,我不想保留堆栈,我想像尾递归一样重用函数。一种部分尾递归。对可以尾递归的部分进行尾递归,并为其他部分增加堆栈大小。 -
你有什么理由要避免蹦床吗?
-
你说的tarmpolining是什么意思?
标签: scala recursion stack-overflow tail-recursion