在Scala中更新环境



我正在使用Scala将一些预定义的语义规则作为生菜语言的解释器来实现。在Multi Let中,我尝试使用两个列表更新环境变量。我对Scala有点陌生,所以我不太确定如何在不将环境变量转换为List的情况下做到这一点。有没有办法在zip函数中操作返回类型?我收到以下错误消息。我的目标是获得一张更新的地图,而不是一张更新地图的列表。

cmd2.sc:44: type mismatch;
found   : List[scala.collection.immutable.Map[String,Helper.this.Value]]
required: Helper.this.Environment
(which expands to)  scala.collection.immutable.Map[String,Helper.this.Value]
evalExpr(e2,newEnv)
^Compilation Failed
sealed trait Expr
case class Const(d: Double) extends Expr
case class Ident(s: String) extends Expr
case class Plus(e1: Expr, e2: Expr) extends Expr
case class Mult(e1: Expr, e2: Expr) extends Expr 
case class Let(id: String, e1: Expr, e2: Expr) extends Expr
case class MultiLet(id: List[String], eList: List[Expr], e2: Expr) extends Expr
sealed trait Value
case class NumValue(f: Double) extends Value
case object Error extends Value /* -- Do not return Error -- simply throw an new IllegalArgumentException whenever you encounter an erroneous case --*/
type Environment = Map[String, Value]
def evalExpr(e: Expr, env: Environment): Value = {

e match {

case Let(x, e1, e2) => {
val v1 = evalExpr(e1, env) 
val newEnv = env.updated(x,v1);
evalExpr(e2,newEnv)
}
case MultiLet(xList, eList, e2) => {
val vList = eList.map(evalExpr(_, env))
val newEnv = (xList, vList).zipped.map{ (x, v) => env.updated(x,v)}
println(newEnv)
evalExpr(e2,newEnv)
}
}
}

我假设我们以以下方式处理Const的情况:

case Const(d) => NumValue(d)

为了获得更新的环境,您需要使用foldLedt:

val newEnv = (xList, vList).zipped.foldLeft(env) { (e, kv) =>
e.updated(kv._1, kv._2)
}

现在让我们测试一下:

启动程序时,环境是空的,因此我们使用空映射运行:

evalExpr(MultiLet(List("1", "2"), List(Const(4), Const(5)), Const(6)), Map.empty)

输出为:

Map(1 -> NumValue(4.0), 2 -> NumValue(5.0))

然后,我们得到一个还没有冲突的函数:

evalExpr(MultiLet(List("2"), List(Const(5)), Const(6)), Map("1" -> NumValue(7)))

输出为:

Map(1 -> NumValue(4.0), 2 -> NumValue(7.0))

最后一种情况是当我们有冲突的变量时:

evalExpr(MultiLet(List("1", "2"), List(Const(4), Const(5)), Const(6)), Map("1" -> NumValue(7)))`

哪个输出:

Map(1 -> NumValue(4.0), 2 -> NumValue(5.0))

代码片段可以在scastie找到。

最新更新