在Scala中更新环境 [英] Updating an Environment in Scala

查看:72
本文介绍了在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆