Updating an Environment in Scala

白昼怎懂夜的黑 提交于 2021-01-29 05:00:25

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!