【问题标题】:Updating an Environment in Scala在 Scala 中更新环境
【发布时间】:2021-01-28 14:32:34
【问题描述】:

我正在采用一些预定义的语义规则,并将它们作为使用 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)
        }
    }
}

【问题讨论】:

  • 您似乎想要foldLeft(env) { case (e, (x, y)) => e.updated(x, y) },或者只是将所有值都放在++。但我认为它不能正常工作:eList.map(evalExpr(_, env)) 将评估旧环境中的所有右手边,但您需要更新的环境才能使所有相互递归的定义正常工作,不是吗?
  • @AndreyTyukin 是正确的。我可能把那部分弄错了。这是一个老问题的建议。我打算先完成case MultiLet ,然后根据我预先构建的测试用例编译整个事情

标签: scala pattern-matching environment interpreter semantics


【解决方案1】:

我假设我们正在通过以下方式处理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))

代码 sn-p 可以在scastie找到。

【讨论】:

  • 你就是那个男人。一切都很完美。我不确定我是否会正确。我不明白为什么更新 e 工作而不是更新 env,类似于 case Let
猜你喜欢
  • 1970-01-01
  • 2018-06-11
  • 1970-01-01
  • 1970-01-01
  • 2022-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多