我有一个 Expr 值,在 Scala 中有两个子 Expr,如何在尾部位置执行它?

I have a Expr value that have two child Expr in Scala, how can I execute this in tail position?

我有一堆 Expr class 定义如下:

sealed trait BoolExpr
sealed trait Value[T] {
  def get: T
}

final case class AndExpr(left: Expr, right: Expr) extends BoolExpr
final case class EqualsExpr[T](value: Value[T], expectedValue: T) extends BoolExpr

在构建了整个 BoolExpr 值之后,我将使用如下函数执行它:

def exec(expr: BoolExpr) = {
  expr match {
    case EqualsExpr(value, expectedValue) => value.get == expectedValue
    case AndExpr(left: Expr, right: Expr) => exec(left) && exec(right)
  }
}

这还不够好,因为它是一个普通的递归。

我打算使用 trampoline 重构 exec 函数。

使用 trampoline 要求每次此函数调用其他内容时,调用都应位于尾部位置,以便在 trampoline 中变形。

但我找不到将 exec(left) && exec(right) 部分重写为尾调用样式的方法。

有什么办法可以做到吗?

你在这里玩蹦床是对的。看看 Cats or Scalaz's Trampoline implementation (which are based on the Free Monad.) Or you can use vanilla Scala in the scala.util.control.TailCalls 包。由于所有这些都是设计的 Monad,您可以执行以下操作:

import util.control.TailCalls._

def exec(expr: BoolExpr) = expr match{
  case EqalsExpr(value, expectedValue) => done(value.get == expectedValue)
  case AndExpr(left, right) => exec(left).flatMap{
    l => exec(right).map(l && _)
  }
}

请注意,调用 mapflatMap 会保留 Trampoline 的属性,永远不会导致堆栈爆炸。