问题
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)
}
}
}
回答1:
I assume that we are dealing the case of Const
the following way:
case Const(d) => NumValue(d)
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)
The output is:
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)))
The output is:
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)))`
Which outputs:
Map(1 -> NumValue(4.0), 2 -> NumValue(5.0))
Code snippet can be found at scastie.
来源:https://stackoverflow.com/questions/64349009/updating-an-environment-in-scala