在Scala中更新环境 [英] Updating an Environment in Scala
问题描述
我正在采用一些预定义的语义规则,并使用Scala将其实现为生菜语言的解释器.在Multi-Let中,我试图使用两个列表来更新环境变量.我是Scala的新手,所以我不太确定如何在不将环境变量转换为List的情况下执行此操作.有没有办法在我的zip函数中操纵返回类型?我收到以下错误消息.我的目标是获取一张更新的地图,而不是一张更新的地图.
I'm taking some predefined semantic rules and implementing them as an interpreter for the lettuce language using Scala. In Multi-Let, I'm trying to update an environment variable using two lists. I'm sort of new to Scala so I'm not too sure how to do this without converting the environment variable to a List. Is there a way to manipulate the return type in my zip function? I'm getting the following error message. My goal is to get a single updated map rather than a list of updated maps.
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
的情况:
I assume that we are dealing the case of Const
the following way:
case Const(d) => NumValue(d)
为了获取更新的环境,您需要使用 foldLedt
:
In order to get an updated environment, you need to use foldLedt
:
val newEnv = (xList, vList).zipped.foldLeft(env) { (e, kv) =>
e.updated(kv._1, kv._2)
}
现在让我们对其进行测试:
Let's now test it:
启动程序时,环境为空,因此我们使用的是空映射:
When starting the program, the environment is empty, so we are running with an empty map:
evalExpr(MultiLet(List("1", "2"), List(Const(4), Const(5)), Const(6)), Map.empty)
输出为:
Map(1 -> NumValue(4.0), 2 -> NumValue(5.0))
然后,我们转到一个没有冲突的函数:
Then, we get to a function where do not yet have conflicts:
evalExpr(MultiLet(List("2"), List(Const(5)), Const(6)), Map("1" -> NumValue(7)))
输出为:
Map(1 -> NumValue(4.0), 2 -> NumValue(7.0))
最后一种情况是变量冲突:
And the last case is when we have conflicting variables:
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 中找到.
这篇关于在Scala中更新环境的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!