在 Scala 中更新环境

Updating an Environment in Scala

我正在采用一些预定义的语义规则并将它们实现为使用 Scala 的生菜语言的解释器。在 Multi-Let 中,我尝试使用两个列表更新环境变量。我是 Scala 的新手,所以我不太确定如何在不将环境变量转换为列表的情况下执行此操作。有没有办法在我的 zip 函数中操作 return 类型?我收到以下错误消息。我的目标是获取单个更新地图而不是更新地图列表。

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 找到代码片段。