Instructor:
def f (n:Int) = if n<=1 then 1 else n * f (n-1)def g (n:Int) = f (n) * g (n-1)def h (n:Int) = h (g (n), f (n))def i (n:Int) = n * n
f
g
h
i
n*f(n-1)
f(n) * g(n-1)
int* f(int x) { return &x; }int* g(int x) { int* y = (int*) malloc (sizeof (int)); *y=x; return y; }int main(void) { int* p = f(5); printf("%d\n", *p); int* q = g(5); }
p
q
int* f(int* x) { *x = *x+1; return x; }int main(void) { int x = 5; double y = 5.2; printf("%d\n", *f(&x)); printf("%f\n", *f(&y));}
x
double
int
What is printed in a statically-scoped vs. dynamically-scoped language?
var x:Int = 10def foo() = x = 20def bar() = var x:Int = 30 foo() print(x) def zee() = var x:Int = 40 bar() print(x)print("bar: "); bar(); println(" " + x)print("zee: "); zee(); println(" " + x)print("foo: "); foo(); println(" " + x)
bar: 30 20zee: 30 40 20foo: 20
bar: 20 10zee: 20 40 10foo: 20
enum Expr: case Literal(x:Int) case Variable(n:String, v: Option[Expr]) // TODO
Extend the algebraic datatype for arithmetic expressions with operators +, -, * Are there more than one - operator?
+
-
*
enum Expr: case Literal(x:Int) case Variable(n:String, v: Option[Expr]) case Plus(l: Expr, r: Expr) // l+r case Minus(l: Expr, r: Expr) // l-r case Neg(e: Expr) // -e case Times(l: Expr, r: Expr) // l*r
Finish the toInt method for arithmetic expressions
toInt
enum Expr: case Literal(x:Int) case Variable(n:String, v:Option[Expr]) case Plus(l: Expr, r: Expr) // l+r case Minus(l: Expr, r: Expr) // l-r case Neg(e: Expr) // -e case Times(l: Expr, r: Expr) // l*r
def toInt(e: Expr) : Int = e match case Literal(x) => x case Variable(n, None) => ??? case Variable(_, Some(e)) => toInt(e) // TODO
def toInt(e: Expr) : Int = e match case Literal(x) => x case Variable(n, None) => ??? case Variable(_, Some(e)) => toInt(e) case Plus(l, r) => toInt(l) + toInt(r) case Minus(l, r) => toInt(l) - toInt(r) case Neg(e) => 0-toInt(e) case Times(l, r) => toInt(l) * toInt(r)
What is printed in a call-by-value vs. a call-by-reference language?
def f(a:Int, b:Int) = { a = b b = b + 1}var x = 5var y = 10f(x,y); println(s"x=$x, y=$y")f(x,x); println(s"x=$x")f(x,x+2); println(s"x=$x")
x=5, y=10x=5x=5
x=10, y=11x=11x=13
def f(): String=>String = { var s = "" (t:String) => { s = s + t; s }}val a = f()println(a("x"))println(a("y"))println(a("z"))
a
String=>String
xxyxyz
public class f { private String s = ""; public String fn(String t) { s = s+t; return s; }}f a = new f()System.out.println(a.fn("x"));
def f(): ()=>String=>String = var s = "" () => { var i = 0 (t:String) => { s = s + t + i; i = i+1; s } }end fval factory = f()val a = factory()val b = factory()println(a("x"))println(a("y"))println(b("z"))
b
s
x0
x0y1
x0y1z0
class A: def f() = println("A.f")class B extends A: override def f() = println("B.f") super.f() end f def g() = println("B.g")val b:A = new B() // b:B?b.f()
let a = { f: function() { console.log("A.f"); }}let b = { f: function() { console.log("B.f"); this.__proto__.f(); }, g: function() { console.log("B.g"); }}b.__proto__ = ab.f();
b.g()
val b:B = new B()
B.f A.f
A
B.g
class Aclass B extends Avar as: List[A] = List(new A(), new B())
Which code compiles and why/why not?
val bs: List[B] = as
val bs: List[B] = List(new B(), new B())
as = bs
val a1: Any = as(0) // a1: A // a1: B
List
List[B] <: List[A]
B <: A
val a1: Any = as(0)
val a1: A = as(0)
val a1: B = as(0)
class Aclass B extends Aval as: Array[A] = Array(new A(), new B())
val bs: Array[B] = as
With subtype wildcard
val bs: Array[? <: A] = as
bs(0) = new B()
val b: B = bs(0)
val b: A = bs(0)
val b: Any = bs(0)
With supertype wildcard
val bs: Array[? >: B] = as
bs(0) = new A()
Any
B
function f() { return { a: 1, b: "hello" c: function () { return 2; } }}
f().a
f().d
f().c()
1
undefined
d
2
function f(n) { var fs = []; for (var i = 0; i < n; i++) { var x = i; fs.push(x); } return fs;}
f(3)
[0,1,2]
0
var
var x
let