, , , ,

[SOLVED] Cspb 3155: assignment 6

$25

File Name: Cspb_3155:_assignment_6.zip
File Size: 216.66 KB

Categories: , , , , Tags: , , , ,
5/5 - (1 vote)
5/5 – (1 vote)

Name: WRITE YOUR NAME HERE

// TEST HELPER
def passed(points: Int) {
    require(points >=0)
    if (points == 1) print(s"
*** Tests Passed (1 point) ***
")
    else print(s"
*** Tests Passed ($points points) ***
")
}

Problem 1 (30 Points): Mutual Recursion in Lettuce

In class, we have explored recursive functions in lettuce using the let rec syntax. In this problem, we will explore, mutually recursive function, specifically two mutually recursive functions.

Consider:

let rec 
        pos = function (x) 
                 if (x >= 0)
                 then x
                 else neg(x)
        neg = function (y)
                 if (y <= 0)
                 then pos (1 + y * y)
                 else pos(1 - y)
   in 
     neg(10.0)

The two functions are mutually recursive since pos calls neg and vice-versa. Convince yourself that thhe program must return 82.

1A (5 points): Extending the Abstract Syntax

Consider the grammar specification we have seen thus far.

ProgramExpr||||||||||TopLevel(Expr)Const(Number)Ident(Identifier)Plus(Expr,Expr)Mult(Expr,Expr)Eq(Expr,Expr)Geq(Expr,Expr)IfThenElse(Expr,Expr,Expr)Let(Identifier,Expr,Expr)FunDef(Identifier,Expr)FunCall(Expr,Expr)LetRec(Identifier,Identifier,Expr,Expr)if (expr) then expr else exprlet identifier = expr in exprfunction (identifier-formal-parameter) expr function call – expr(expr)Program→TopLevel(Expr)Expr→Const(Number)|Ident(Identifier)|Plus(Expr,Expr)|Mult(Expr,Expr)|Eq(Expr,Expr)|Geq(Expr,Expr)|IfThenElse(Expr,Expr,Expr)if (expr) then expr else expr|Let(Identifier,Expr,Expr)let identifier = expr in expr|FunDef(Identifier,Expr)function (identifier-formal-parameter) expr |FunCall(Expr,Expr)function call – expr(expr)|LetRec(Identifier,Identifier,Expr,Expr)

We wish to add a new rule for two mutually recursive functions

Expr  LetRec2(Identifier,Identifier,Expr,Identifier,Identifier,Expr,Expr)Expr → LetRec2(Identifier,Identifier,Expr,Identifier,Identifier,Expr,Expr)

Such that a mutual call such as

let rec 
         f1 = function (x1) e1
         f2 = function (x2) e2
     in 
         e3

is represented in the AST as

LetRec2(f1, x1, e1, f2, x2, e2, e3)

Extend the existing AST specification to add support for LetRec2.

sealed trait Program
sealed trait Expr
case class Const(f: Double) extends Expr
case class Ident(s: String) extends Expr
case class Minus(e1: Expr, e2: Expr) extends Expr
case class Plus(e1: Expr, e2: Expr) extends Expr
case class Mult(e1: Expr, e2: Expr) extends Expr
case class Eq(e1: Expr, e2: Expr) extends Expr
case class Geq(e1: Expr, e2: Expr) extends Expr
case class IfThenElse(e1: Expr, e2: Expr, e3: Expr) extends Expr
case class Let(x: String, e1: Expr, e2: Expr) extends Expr
case class FunDef(id: String, e: Expr) extends Expr
case class FunCall(calledFun: Expr, argExpr: Expr) extends Expr
case class LetRec(funName: String, param: String, funExpr: Expr, bodyExpr: Expr) extends Expr

??? // YOUR CODE HERE
case class TopLevel(e: Expr) extends Program
//BEGIN TEST
val x = Ident("x")
val y = Ident("y")
val foo = Ident("foo")
val bar = Ident("bar")

val e1 = IfThenElse( Geq(x, Const(0.0)), x, FunCall(bar, Plus(x, Const(1.0)))) // if x >= 0 then x else bar(1 + x)
val e2 = IfThenElse( Geq(Const(1.0), x), Plus(Const(2.0), x), FunCall(foo, Minus(x, Const(2.0)))) // if 1 >= x then 2 + x else foo(x-2)
val e3 = FunCall(bar, Const(10))
val lr2 = LetRec2("foo", "x", e1, "bar", "x", e2, e3)
val p1 = TopLevel(lr2)
passed(3)
//END TEST
//BEGIN TEST
val x = Ident("x")
val y = Ident("y")
val foo = Ident("foo")
val bar = Ident("bar")
val e11 = IfThenElse(Geq(x, Const(0.0)), FunCall(bar, Minus(Const(1.0), x)),Mult(x, FunCall(foo,  Minus(x, Const(1.0))) ))
val e1 = IfThenElse(Eq(x, Const(0.0)), Const(1.0), e11)
val e2 = IfThenElse(Geq(Const(0.0), y), Mult(Const(-0.5), y) , FunCall(foo, y))
val e3 = FunCall(foo, Const(10.5))
val lr3 = LetRec2("foo", "x", e1, "bar", "y", e2, e3)
passed(2)
//END TEST

1B (10 points): Build an Environment to Handle Mutual Recursion

In class we saw how to build an environment that handles recursive calls using the ExtendRec construct.

Now we propose an ExtendMutualRec2 construct such that

eval(LetRec2(f1, x1, e1, f2, x2, e2, e),σ)=eval(e,ExtendMutualRec2(σ,f1, x1, e1, f2, x2, e2))((Mutual-Rec-OK)eval(LetRec2(f1, x1, e1, f2, x2, e2, e),σ)=eval(e,ExtendMutualRec2(σ,f1, x1, e1, f2, x2, e2))((Mutual-Rec-OK)

Complete the mathematical specification of ExtendMutualRec2ExtendMutualRec2. Let π=ExtendMutualRec2(σ,f1, x1, e1, f2, x2, e2))π=ExtendMutualRec2(σ,f1, x1, e1, f2, x2, e2)).

π(y)=⎧⎩⎨123if y=f1if y=f2otherwiseπ(y)={1if y=f12if y=f23otherwise

Fill in the appropriate values for 1,2,31,2,3.

Write your answer in the cell bellow. You can make a numbered list in markdown to represent your answers as follows:

  1. First
  2. Second
  3. And so on…

YOUR ANSWER HERE

1C (9 points): Code up the Environment Spec

Implement the environment for ExtendMutualRec.

sealed trait Environment 
sealed trait Value

case object EmptyEnv extends Environment
case class Extend(x: String, v: Value, sigma: Environment) extends Environment
case class ExtendRec(f: String, x: String, e: Expr, sigma: Environment ) extends Environment
case class ExtendMutualRec2(
    ??? // YOUR CODE HERE
) extends Environment

/* -- We need to redefine values to accomodate the new representation of environments --*/
case class NumValue(d: Double) extends Value
case class BoolValue(b: Boolean) extends Value
case class Closure(x: String, e: Expr, pi: Environment) extends Value
case object ErrorValue extends Value


/*2. Operators on values */

def valueToNumber(v: Value): Double = v match {
    case NumValue(d) => d
    case _ => throw new IllegalArgumentException(s"Error: Asking me to convert Value: $v to a number")
}

def valueToBoolean(v: Value): Boolean = v match {
    case BoolValue(b) => b
    case _ => throw new IllegalArgumentException(s"Error: Asking me to convert Value: $v to a boolean")
}

def valueToClosure(v: Value): Closure = v match {
    case Closure(x, e, pi) => Closure(x, e, pi)
    case _ =>  throw new IllegalArgumentException(s"Error: Asking me to convert Value: $v to a closure")
}


/*-- Operations on environments --*/

def lookupEnv(pi: Environment, x: String): Value = pi match {
    case EmptyEnv => throw new IllegalArgumentException(s"Error could not find string $x in environment")
    case Extend(y, v, _) if y == x => v
    case Extend(_, _, sigma) => lookupEnv(sigma, x)
    case ExtendRec(f, y, e, sigma) => if (x == f) 
                                          Closure(y, e, pi)
                                   else
                                          lookupEnv(sigma, x)
    case ExtendMutualRec2(f1, x1, e1, f2, x2, e2, sigma ) => 
    {
        ??? // YOUR CODE HERE
    }
}
// BEGIN TEST
val env: Environment = ExtendMutualRec2("f1", "x1", Const(0.0), "f2", "x2", Const(0.0), EmptyEnv)
passed(4)
// END TEST
// BEGIN TEST
val env: Environment = ExtendMutualRec2("f1", "x1", Const(0.0), "f2", "x2", Const(0.0), EmptyEnv)
// Ensure looking up either function gets us the right value, no matter how many times we recurse.
val f1 @ Closure(_, _, pi1) = lookupEnv(env, "f1")
val f2 @ Closure(_, _, pi2) = lookupEnv(env, "f2")
lookupEnv(pi1, "f1") == f1
lookupEnv(pi1, "f2") == f2
lookupEnv(pi2, "f2") == f1
lookupEnv(pi2, "f2") == f2
passed(5)
// END TEST

1D (6 points): Interpreter

Complete the interpreter for this new node.

def evalExpr(e: Expr, env: Environment): Value =  {
    
    /* Method to deal with binary arithmetic operations */
    def applyArith2 (e1: Expr, e2: Expr) (fun: (Double , Double) => Double) = {
        val v1 = valueToNumber(evalExpr(e1, env))
        val v2 = valueToNumber(evalExpr(e2, env))
        val v3 = fun(v1, v2)
        NumValue(v3)
    }  /* -- We have deliberately curried the method --*/
    
    /* Helper method to deal with unary arithmetic */
    def applyArith1(e: Expr) (fun: Double => Double) = {
        val v = valueToNumber(evalExpr(e, env))
        val v1 = fun(v)
        NumValue(v1)
    }
    
    /* Helper method to deal with comparison operators */
    def applyComp(e1: Expr, e2: Expr) (fun: (Double, Double) => Boolean) = {
        val v1 = valueToNumber(evalExpr(e1, env))
        val v2 = valueToNumber(evalExpr(e2, env))
        val v3 = fun(v1, v2)
        BoolValue(v3)
    }
    
   
    e match {
        case Const(f) => NumValue(f) // Same as before
        
        case Ident(x) => lookupEnv(env, x) // Changed to accomodate the new environment definitions.
    
        /* Ditto as before */
        case Plus(e1, e2) => applyArith2 (e1, e2) ( _ + _ )
        /* Ditto as before */
        case Minus(e1, e2) => applyArith2(e1, e2) ( _ - _ )
        /* Ditto as before */
        case Mult(e1, e2) =>  applyArith2(e1, e2) (_ * _)
        /* Ditto as before */
        case Geq(e1, e2) => applyComp(e1, e2)(_ >= _)
        /* Ditto as before */
        case Eq(e1, e2) => applyComp(e1, e2)(_ == _)
        /* Ditto as before */
        case IfThenElse(e1, e2, e3) => {
            val v = evalExpr(e1, env)
            v match {
                case BoolValue(true) => evalExpr(e2, env)
                case BoolValue(false) => evalExpr(e3, env)
                case _ => throw new IllegalArgumentException(s"If-then-else condition expr: ${e1} is non-boolean -- evaluates to ${v}")
            }
        }
        /* Ditto as before */
        case Let(x, e1, e2) => {
            val v1 = evalExpr(e1, env)  // eval e1
            val env2 = Extend(x, v1, env) // create a new extended env
            evalExpr(e2, env2) // eval e2 under that.
        }
        /* Ditto as before */
        case FunDef(x, e) => {
            Closure(x, e, env) // Return a closure with the current enviroment.
        }
        /* Ditto as before */
        case FunCall(e1, e2) => {
            val v1 = evalExpr(e1, env)
            val v2 = evalExpr(e2, env)
            v1 match {
                case Closure(x, closure_ex, closed_env) => {
                    // First extend closed_env by binding x to v2
                    val new_env = Extend(x, v2, closed_env)
                    // Evaluate the body of the closure under the extended environment.
                    evalExpr(closure_ex, new_env)
                }
                case _ => throw new IllegalArgumentException(s"Function call error: expression $e1 does not evaluate to a closure")
            }
        }
    
        case LetRec(rfun, x, fExpr, bExpr) => {
            val env2 = ExtendRec(rfun, x, fExpr, env)
            evalExpr(bExpr, env2)
        }
        
        case LetRec2(f1, x1, e1, f2, x2, e2, e) => {
            ??? // YOUR CODE HERE
        }
    }
}

def evalProgram(p: Program) = {
    p match { 
        case TopLevel(e) => evalExpr(e, EmptyEnv)
    }
}
//BEGIN TEST
val x = Ident("x")
val y = Ident("y")
val foo = Ident("foo")
val bar = Ident("bar")

val e1 = IfThenElse( Geq(x, Const(0.0)), x, FunCall(bar, Plus(x, Const(1.0)))) // if x >= 0 then x else bar(1 + x)
val e2 = IfThenElse( Geq(Const(1.0), x), Plus(Const(2.0), x), FunCall(foo, Minus(x, Const(2.0)))) // if 1 >= x then 2 + x else foo(x-2)
val e3 = FunCall(bar, Const(10))

val lr2 = LetRec2("foo", "x", e1, "bar", "x", e2, e3)
val p1 = TopLevel(lr2)
assert(evalProgram(p1) == NumValue(8.0), "Test 1 of Set 1 failed")

val e4 = FunCall(foo, Const(12.0))
val p2 = TopLevel(LetRec2("foo", "x", e1, "bar", "x", e2, e4))
assert(evalProgram(p2) == NumValue(12.0), "Test 2 of Set 1 failed")

val e5 = FunCall(foo, Const(-12.0))
val p3 = TopLevel(LetRec2("foo", "x", e1, "bar", "x", e2, e5))
assert(evalProgram(p3) == NumValue(-9.0), "Test 3 of Set 1 failed")

val e6 = FunCall(bar, Const(-12.0))
val p4 = TopLevel(LetRec2("foo", "x", e1, "bar", "x", e2, e6))
assert(evalProgram(p4) == NumValue(-10.0), "Test 4 of Set 1 failed")

val e7 = FunCall(bar, Const(1.9))
val p5 = TopLevel(LetRec2("foo", "x", e1, "bar", "x", e2, e7))
assert(evalProgram(p5) == NumValue(2.9), "Test 5 of Set 1 failed")

passed(3)
//END TEST
//BEGIN TEST 
/*
let rec 
        pos = function (x) 
                 if (x >= 0)
                 then
                    if (x <= 0.5)
                     then x
                     else 0.5 + pos(x-1)
                 else neg(x)
        neg = function (y)
                 if (y <= 0)
                 then pos (1 + y * y)
                 else pos(1 - y)
   in 
     ...
*/

val x = Ident("x")
val y = Ident("y")
val pos = Ident("pos")
val neg = Ident("neg")

val e11 = IfThenElse(Geq(Const(0.5), x), x, Plus(Const(0.5), FunCall(pos, Minus(x, Const(1.0)))))
val e1 = IfThenElse(Geq(x, Const(0.0)), e11, FunCall(neg, x))
val e2 = IfThenElse(Geq(Const(0.0), y), FunCall(pos, Plus(Const(1.0), Mult(y,y))), FunCall(pos, Minus(Const(1.0), y)))

val t1 = FunCall(neg, Const(10.0))
val lr1 = LetRec2("pos", "x", e1, "neg", "y", e2, t1)
val p1 = TopLevel(lr1)
assert(evalProgram(p1) == NumValue(41.0), "Test 1 of set 2 failed")

val t2 = FunCall(pos, Const(-8.0))
val lr2 = LetRec2("pos", "x", e1, "neg", "y", e2, t2)
val p2 = TopLevel(lr2)
assert(evalProgram(p2) == NumValue(32.5), "Test 2 of set 2 failed")


val t3 = FunCall(pos, Const(-0.5))
val lr3 = LetRec2("pos", "x", e1, "neg", "y", e2, t3)
val p3 = TopLevel(lr3)
assert(evalProgram(p3) == NumValue(0.75), "Test 3 of set 2 failed")

passed(3)
//END TEST

Problem 2 (15 points): Block of Statements in Lettuce with References.

You have been using a sequence of statements in almost all languages that you have learned but for Lettuce. If we write a sequence of expressions (statements) as follows

<expression 1> ;
<expression 2> ;
<expression 3> ;
<expression 4> ;
... 
<expression n>

Each of these expressions is interpreted in sequence starting from 1 to n. The return value of the entire block of expressions (statements) is simply the value returned by the very last statement.

We would like to add this to Lettuce in the form of a new production.

Expr  Seq(Expr,Expr)Expr → Seq(Expr,Expr)

The expression Seq(e1, e2)Seq(e1, e2) is a sequence e1 followed by e2. The overall value of a Seq is that returned by e2. However, since we have Lettuce with references, it is possible that e1 may have side effects that are visible in e2.

Longer compositions can be obtained by nesting Seq.

Seq( e1, Seq(e2, Seq(e3, Seq(e4, e5))))

2A (5 points): Extend the abstract syntax with Seq

sealed trait Program
sealed trait Expr

case class TopLevel(e: Expr) extends Program

case class Const(v: Double) extends Expr // Expr -> Const(v)
case class Ident(s: String) extends Expr // Expr -> Ident(s)

// Arithmetic Expressions
case class Plus(e1: Expr, e2: Expr) extends Expr // Expr -> Plus(Expr, Expr)
case class Minus(e1: Expr, e2: Expr) extends Expr // Expr -> Minus(Expr, Expr)
case class Mult(e1: Expr, e2: Expr) extends Expr // Expr -> Mult (Expr, Expr)

// Boolean Expressions
case class Geq(e1: Expr, e2:Expr) extends Expr
case class Eq(e1: Expr, e2: Expr) extends Expr

//If then else
case class IfThenElse(e: Expr, eIf: Expr, eElse: Expr) extends Expr

//Let bindings
case class Let(s: String, defExpr: Expr, bodyExpr: Expr) extends Expr

//Function definition
case class FunDef(param: String, bodyExpr: Expr) extends Expr

// Function call
case class FunCall(funCalled: Expr, argExpr: Expr) extends Expr

// New Ref
case class NewRef(e: Expr) extends Expr

//DeRef
case class DeRef(lval: Expr) extends Expr

//AssignRef
case class AssignRef(lval: Expr, rval: Expr) extends Expr

// Seq
??? // YOUR CODE HERE
//BEGIN TEST
val s1 = Seq(Const(10.0), NewRef(Const(15.0)))
val s2 = Seq(DeRef(NewRef(Const(20.0))), Let("x", DeRef(NewRef(Const(25.0))), Ident("x")))
val s3 = Seq(Const(10.0), Seq(Const(25.0), Const(35.0)))
val s4 = Seq(Seq(Const(5.0), Const(10.0)),  Seq(Const(25.0), Const(35.0)) )

passed(5)
//END TEST

2B (5 Points): Write Semantics

We would like to write a semantic rule for evaluating Seq(e1, e2)Seq(e1, e2). Complete the rules for the OK and error cases by filling in the ??? marks below.

eval(e1,σ,s)=(v1,s1),v1error,eval(e2,σ,1)=(v2,s2)eval(Seq(e1, e2),σ,s)=2(seq-ok)eval(e1,σ,s)=(v1,s1),v1≠error,eval(e2,σ,1)=(v2,s2)eval(Seq(e1, e2),σ,s)=2(seq-ok)
eval(e1,σ,s)=(v1,s1),v1=erroreval(Seq(e1, e2),σ,s)=3(seq-nok)eval(e1,σ,s)=(v1,s1),v1=erroreval(Seq(e1, e2),σ,s)=3(seq-nok)

Fill in the appropriate values for 1,2,31,2,3.

Write your answer in the cell bellow. You can make a numbered list in markdown to represent your answers as follows:

  1. First
  2. Second
  3. And so on…

YOUR ANSWER HERE

2C (5 points): Implement the code

Extend the implementation of the interpreter from the notebook on references to add support for Seq.

sealed trait Value
/*-- Now we can finish the rest --*/
case class NumValue(f: Double) extends Value
case class BoolValue(b: Boolean) extends Value
/*-- Note: to get recursion working, we will need to make environments different --*/
case class Closure(x: String, e: Expr, pi: Map[String, Value]) extends Value 
/* -- references are here -- */
case class Reference(j: Int) extends Value
case object ErrorValue extends Value
/*2. Operators on values */
def valueToNumber(v: Value): Double = v match {
    case NumValue(d) => d
    case _ => throw new IllegalArgumentException(s"Error: Asking me to convert Value: $v to a number")
}
def valueToBoolean(v: Value): Boolean = v match {
    case BoolValue(b) => b
    case _ => throw new IllegalArgumentException(s"Error: Asking me to convert Value: $v to a boolean")
}
def valueToClosure(v: Value): Closure = v match {
    case Closure(x, e, pi) => Closure(x, e, pi)
    case _ =>  throw new IllegalArgumentException(s"Error: Asking me to convert Value: $v to a closure")
}

/*3. Immutable Store */
case class ImmutableStore(val nCells: Int, val storeMap: Map[Int, Value])
def createNewCell(s: ImmutableStore, v: Value): (ImmutableStore, Int) = {
        /*- make a new cell -*/
        val j = s.nCells
        val nMap = s.storeMap + (j -> v)
        val nStore = ImmutableStore(s.nCells + 1, nMap) // Make a new store with one more cell
        (nStore, j)
}
def lookupCellValue(s: ImmutableStore, j: Int): Value = {
        if (s.storeMap.contains(j)){
            s.storeMap(j)
        } else {
            throw new IllegalArgumentException(s"Illegal lookup of nonexistant location $j")
        }
}
def assignToCell(s: ImmutableStore, j: Int, v: Value): ImmutableStore = {
        if (s.storeMap.contains(j)){
            val nMap = s.storeMap + (j -> v) // Update the store map.
            ImmutableStore(s.nCells, nMap)
        } else {
            throw new IllegalArgumentException(s"Illegal assignment to nonexistent location $j")
        }
    }
    
def evalExpr(e: Expr, env: Map[String, Value], store: ImmutableStore): (Value, ImmutableStore) = {
      /* Method to deal with binary arithmetic operations */
    
    def applyArith2 (e1: Expr, e2: Expr) (fun: (Double , Double) => Double) = {
        val (v1, store1) = evalExpr(e1, env, store)
        val (v2, store2) = evalExpr(e2, env, store1)
        val v3 = fun(valueToNumber(v1), valueToNumber(v2))
        (NumValue(v3), store2)
    }  /* -- We have deliberately curried the method --*/
    
    /* Helper method to deal with unary arithmetic */
    def applyArith1(e: Expr) (fun: Double => Double) = {
        val (v,store1) = evalExpr(e, env, store)
        val v1 = fun(valueToNumber(v))
        (NumValue(v1), store1)
    }
    
    /* Helper method to deal with comparison operators */
    def applyComp(e1: Expr, e2: Expr) (fun: (Double, Double) => Boolean) = {
        val (v1, store1) = evalExpr(e1, env, store)
        val (v2, store2) = evalExpr(e2, env, store1)
        val v3 = fun(valueToNumber(v1), valueToNumber(v2))
        (BoolValue(v3), store2)
    }
    
    e match {
        case Const(f) => (NumValue(f), store)
        
        case Ident(x) => {
            if (env contains x) 
                (env(x), store)
            else 
                throw new IllegalArgumentException(s"Undefined identifier $x")
        }
    
    
        case Plus(e1, e2) => applyArith2 (e1, e2) ( _ + _ )
            
        case Minus(e1, e2) => applyArith2(e1, e2) ( _ - _ )
    
        case Mult(e1, e2) =>  applyArith2(e1, e2) (_ * _)
        
        case Geq(e1, e2) => applyComp(e1, e2)(_ >= _)
    
        case Eq(e1, e2) => applyComp(e1, e2)(_ == _)
        
        case IfThenElse(e1, e2, e3) => {
            val (v, store1) = evalExpr(e1, env, store)
            v match {
                case BoolValue(true) => evalExpr(e2, env, store1)
                case BoolValue(false) => evalExpr(e3, env, store1)
                case _ => throw new IllegalArgumentException(s"If-then-else condition expr: ${e1} is non-boolean -- evaluates to ${v}")
            }
        }
        
        case Let(x, e1, e2) => {
            val (v1, store1) = evalExpr(e1, env, store)  // eval e1
            val env2 = env + (x -> v1) // create a new extended env
            evalExpr(e2, env2, store1) // eval e2 under that.
        }
    
        case FunDef(x, e) => {
            (Closure(x, e, env), store) // Return a closure with the current enviroment.
        }
        
        case FunCall(e1, e2) => {
            val (v1, store1) = evalExpr(e1, env, store)
            val (v2, store2) = evalExpr(e2, env, store1)
            v1 match {
                case Closure(x, closure_ex, closed_env) => {
                    // First extend closed_env by binding x to v2
                    val new_env = closed_env + ( x -> v2)
                    // Evaluate the body of the closure under the extended environment.
                    evalExpr(closure_ex, new_env, store2)
                }
                case _ => throw new IllegalArgumentException(s"Function call error: expression $e1 does not evaluate to a closure")
            }
        }
        
        case NewRef(e) => {
            val (v, store1) = evalExpr(e, env, store)
            val (store2, j) = createNewCell(store1, v)
            (Reference(j), store2)
        }
        
        case DeRef(e) => {
            val (v, store1) = evalExpr(e, env, store)
            v match {
                case Reference(j) => {
                    val v = lookupCellValue(store1, j)
                    (v, store1)
                }
                case _ => throw new IllegalArgumentException(s"Deref applied to an expression that does not evaluate to a reference")
            }
        }
        
        case AssignRef(e1, e2) => {
            val (v1, store1) = evalExpr(e1, env, store)
            v1 match {
                case Reference(j) => {
                    val (v2, store2) = evalExpr(e2, env, store1)
                    val store3 = assignToCell(store2, j, v2)
                    (v2, store3)
                }
                case _ => throw new IllegalArgumentException(s"AssignRef applied to argument that is not a reference")
                
            }
        }
        
        case Seq(e1, e2) => {
            ??? // YOUR CODE HERE
        }
        
    }

}

def evalProgram(p: Program) = p match {
        case TopLevel(e) => { 
            // Start with empty environment and empty store
            val (v1, s1) = evalExpr(e, Map(), new ImmutableStore(0, Map()))
            v1
        }
}
    
//BEGIN TEST

val incr = Ident("incr")
val decr = Ident("decr")
val zero = Ident("zero")
val r = Ident("r")
val x = Ident("x")
val e4 = Seq(Seq(Seq(FunCall(zero, r), FunCall(incr, r)), Seq(FunCall(incr, r), FunCall(incr, r))), Seq(FunCall(decr, r), FunCall(decr,r)))
val rr = Let("r", NewRef(Const(15.0)), e4)
val z = Let("zero", FunDef("x", AssignRef(x, Const(0.0))), rr)
val d = Let("decr", FunDef("x", AssignRef(x, Minus(DeRef(x), Const(1.0)))), z)
val i = Let("incr",FunDef("x", AssignRef(x, Plus(DeRef(x), Const(1.0)))), d )
val prog = TopLevel(i)
             
assert(evalProgram(prog) == NumValue(1.0), "Test 1 Set 3 Failed")

passed(5)
//END TEST

Reviews

There are no reviews yet.

Only logged in customers who have purchased this product may leave a review.

Shopping Cart
[SOLVED] Cspb 3155: assignment 6
$25