class Example // Java
{
private int foo;
public void fun(double foo)
{
System.out.println(foo); // Which foo?
}
public void fun()
{
System.out.println(foo); // Which foo?
}
}
def fun(x : Int) { // Scala
def helper() { var x : Int; ... }
...
}
val x = 1;
def f(y) = x + y;
def g() { val x = 2; f(x) };
g()
val x = 1;
def f(y) = x + y;
def g() { val x = 2; f(x) };
g()
x -> 1 // first def. of x x -> 2, x -> 1 // def. of x inside g y -> 2, x -> 2, x -> 1 // def. of parameter y
val x = 1;
def f(y) = x + y; // x -> 1
def g() { val x = 2; f(0) }; // f -> ...
Table only needs to store free variables in function body
y -> 2, x -> 1
val:
val fac = x => if (x == 0) 1 else x * fac(x - 1)
fac
x => if (x == 0) 1 else x * fac(x - 1)
fac is defineddef simultaneously adds fac and RHS to
symbol table
case class Closure(params : List[String], body : Block, var env : List[(String, Any)])
...
def evalDef(symbols : List[(String, Any)], defn : Definition) =
defn match {
case Defdef(name, Function(params, body)) => {
val cl = Closure(params, body, symbols)
val syms = (name, cl) :: symbols
cl.env = syms // mutation
syms
}
...
}
var in the interpreter.

varname=initialValue
function funname {
. . .
}
Function parameters are not named. Instead, you refer to them as
$1, $2, $3...
funname arg1 arg2 arg3 . . .
local varname=initialValue
$varname
For example, the command
echo $a
prints the value of a
x="2"
function f {
echo $x
}
function main {
local x="3" ;
f ;
}
main
x="2"
function f {
echo $x
}
function g {
local x="3" ;
f ;
}
function main {
local x="4" ;
f ;
g ;
f ;
}
f ;
main
What do you expect this program to print?
val a = 3;
val f = { x => x * a };
val g = { a => a * f(a)};
g(1)
What result output do you expect?
case Valdef(name, Function(params, body)) => { (name, Closure(params, body, symbols)) :: symbols }
Run the debugger with the same program as input. When the breakpoint is
hit, inspect symbols. What do you get for symbols
when the definitions of f and g are evaluated?
case Funcall(fun, args) => eval(fun, symbols) match
to
case Funcall(fun, args) => val funval = eval(fun, symbols); funval match
Debug the program again, this time with a breakpoint in the line
evalBlock(body, params.zip(args.map(eval(_, symbols))) ::: syms)
The breakpoint will be triggered when g and
f are executed/ What are the values of symbols
and the syms in the closure object when g is
executed?
f executed? I had to work a bit to make SL1 use static scoping. Undo this to make an interpreter that uses dynamic scoping.
case class Closurecase Valdef(name, Function(params, body)) => { (name, Closure(params, body, symbols)) :: symbols }
so that the line below will simply add the Function object
to the table
case Function(params, body) => Closure(params, body, symbols)
so that the line below will simply cause a Function to
evaluate to itself
Defdef case of evalDef for now. (It
mutates the env field of the closure. This would need to be
solved by mutating the symbol table entry, as in homework 3, but in this
lab step, we just won't use def.)case Closure(params, body, syms) => evalBlock(body, params.zip(args.map(eval(_, symbols))) ::: syms)
to
case Function(params, body) => evalBlock(body, params.zip(args.map(eval(_, symbols))) ::: symbols)
test1.bash into SL1dyn. What is your
test case? What is the result?