1
1 + 2
enum Expr:
1 + 2
enum Expr: case Num()
1 + 2
enum Expr: case Num(value: Int)
1 + 2
enum Expr: case Num(value: Int) case Add()
1 + 2
enum Expr: case Num(value: Int) case Add(lhs: Num)
1 + 2
enum Expr: case Num(value: Int) case Add(lhs: Num, rhs: Num)
1 + 2
Num value ⇓ ???
1 + 2
Num value ⇓ ???
1 + 2
Num value ⇓ ???
1 + 2
Num value ⇓ value
1 + 2
Add lhs rhs ⇓ ???
1 + 2
Add lhs rhs ⇓ ???
1 + 2
Add lhs rhs ⇓ lhs + rhs
1 + 2
Add lhs rhs ⇓ lhs + rhs
1 + 2
lhs ⇓ v₁Add lhs rhs ⇓ lhs + rhs
1 + 2
lhs ⇓ v₁ rhs ⇓ v₂Add lhs rhs ⇓ lhs + rhs
1 + 2
lhs ⇓ v₁ rhs ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Add lhs rhs ⇓ lhs + rhs
1 + 2
lhs ⇓ v₁ rhs ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Add lhs rhs ⇓ lhs + rhs
1 + 2
lhs ⇓ v₁ rhs ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Add lhs rhs ⇓ v₁ + v₂
1 + 2
def interpret(expr: Expr): ??? =
def interpret(expr: Expr): ??? =
def interpret(expr: Expr): ??? =
def interpret(expr: Expr): Int =
def interpret(expr: Expr): Int = expr match
def interpret(expr: Expr): Int = expr match case Num(value) =>
Num value ⇓ value
def interpret(expr: Expr): Int = expr match case Num(value) => value
Num value ⇓ value
def interpret(expr: Expr): Int = expr match case Num(value) => value case Add(lhs, rhs) =>
lhs ⇓ v₁ rhs ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Add lhs rhs ⇓ v₁ + v₂
def interpret(expr: Expr): Int = expr match case Num(value) => value case Add(lhs, rhs) => add(lhs, rhs)
lhs ⇓ v₁ rhs ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Add lhs rhs ⇓ v₁ + v₂
def add(lhs: Num, rhs: Num) =
lhs ⇓ v₁ rhs ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Add lhs rhs ⇓ v₁ + v₂
def add(lhs: Num, rhs: Num) = val v1 = interpret(lhs)
lhs ⇓ v₁ rhs ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Add lhs rhs ⇓ v₁ + v₂
def add(lhs: Num, rhs: Num) = val v1 = interpret(lhs) val v2 = interpret(rhs)
lhs ⇓ v₁ rhs ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Add lhs rhs ⇓ v₁ + v₂
def add(lhs: Num, rhs: Num) = val v1 = interpret(lhs) val v2 = interpret(rhs) v1 + v2
lhs ⇓ v₁ rhs ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Add lhs rhs ⇓ v₁ + v₂
1 + 2
val expr = Add(Num(1), Num(2))
interpret(expr)
1 + 2
val expr = Add(Num(1), Num(2))
interpret(expr)
1 + 2
val expr = Add(Num(1), Num(2))
interpret(expr)
1 + 2
val expr = Add(Num(1), Num(2))
interpret(expr)
1 + 2
val expr = Add(Num(1), Num(2))
interpret(expr)// val res0: Int = 3
(1 + 2)
val expr = Add(Num(1), Num(2))
interpret(expr)// val res0: Int = 3
((1) + ((2)))
val expr = Add(Num(1), Num(2))
interpret(expr)// val res0: Int = 3
1 + 2
1 + 2
1 + 2
1 + 2
1 + (2 + 3)
enum Expr: case Num(value: Int) case Add(lhs: Num, rhs: Num)
enum Expr: case Num(value: Int) case Add(lhs: Expr, rhs: Expr)
def add(lhs: Num, rhs: Num) = val v1 = interpret(lhs) val v2 = interpret(rhs) v1 + v2
lhs ⇓ v₁ rhs ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Add lhs rhs ⇓ v₁ + v₂
def add(lhs: Num, rhs: Num) = val v1 = interpret(lhs) val v2 = interpret(rhs) v1 + v2
lhs ⇓ v₁ rhs ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Add lhs rhs ⇓ v₁ + v₂
def add(lhs: Expr, rhs: Expr) = val v1 = interpret(lhs) val v2 = interpret(rhs) v1 + v2
lhs ⇓ v₁ rhs ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Add lhs rhs ⇓ v₁ + v₂
def add(lhs: Expr, rhs: Expr) = val v1 = interpret(lhs) val v2 = interpret(rhs) v1 + v2
lhs ⇓ v₁ rhs ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Add lhs rhs ⇓ v₁ + v₂
def add(lhs: Expr, rhs: Expr) = val v1 = interpret(lhs) val v2 = interpret(rhs) v1 + v2
lhs ⇓ v₁ rhs ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Add lhs rhs ⇓ v₁ + v₂
1 + 2
val expr = Add(Num(1), Num(2))
interpret(expr)
1 + 2
val expr = Add(Num(1), Num(2))
interpret(expr)
1 + (2 + 3)
val expr = Add(Num(1), Add(Num(2), Num(3)))
interpret(expr)
1 + (2 + 3)
val expr = Add(Num(1), Add(Num(2), Num(3)))
interpret(expr)// val res1: Int = 6
Source code is represented as a recursive sum type
This is called an AST
Interpretation is done through pattern matching
if true then 1 + 2 else 3 + 4
if true then 1 + 2 else 3 + 4
if true then 1 + 2 else 3 + 4
if true then 1 + 2 else 3 + 4
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond ⇓ ???
if true then 1 + 2 else 3 + 4
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred ⇓ ???
if true then 1 + 2 else 3 + 4
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT ⇓ ???
if true then 1 + 2 else 3 + 4
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ ???
if true then 1 + 2 else 3 + 4
pred ⇓ ???⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ ???
if true then 1 + 2 else 3 + 4
pred ⇓ ???⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ ???
if true then 1 + 2 else 3 + 4
pred ⇓ true⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ ???pred ⇓ false⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ ???
if true then 1 + 2 else 3 + 4
pred ⇓ true⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ ???pred ⇓ false⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ ???
if true then 1 + 2 else 3 + 4
pred ⇓ true⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ ???pred ⇓ false⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ ???
if true then 1 + 2 else 3 + 4
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ ???pred ⇓ false⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ ???
if true then 1 + 2 else 3 + 4
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ ???pred ⇓ false⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ ???
if true then 1 + 2 else 3 + 4
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ ???
if true then 1 + 2 else 3 + 4
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ ???
if true then 1 + 2 else 3 + 4
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ ???
if true then 1 + 2 else 3 + 4
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ ???
if true then 1 + 2 else 3 + 4
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
if true then 1 + 2 else 3 + 4
enum Expr: case Num(value: Int) case Add(lhs: Expr, rhs: Expr)
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
enum Expr: case Num(value: Int) case Add(lhs: Expr, rhs: Expr) case Cond()
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
enum Expr: case Num(value: Int) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr)
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
enum Expr: case Num(value: Int) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr)
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
enum Expr: case Num(value: Int) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr)
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def interpret(expr: Expr): Int = expr match case Num(value) => value case Add(lhs, rhs) => add(lhs, rhs)
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def interpret(expr: Expr): Int = expr match case Num(value) => value case Add(lhs, rhs) => add(lhs, rhs) case Cond(pred, onT, onF) => cond(pred, onT, onF)
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def cond(pred: Expr, onT: Expr, onF: Expr) =
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def cond(pred: Expr, onT: Expr, onF: Expr) = if interpret(pred) then
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def cond(pred: Expr, onT: Expr, onF: Expr) = if interpret(pred) then interpret(onT)
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def cond(pred: Expr, onT: Expr, onF: Expr) = if interpret(pred) then interpret(onT) else interpret(onF)
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def cond(pred: Expr, onT: Expr, onF: Expr) = if interpret(pred) then interpret(onT) else interpret(onF)
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def cond(pred: Expr, onT: Expr, onF: Expr) = if interpret(pred) != 0 then interpret(onT) else interpret(onF)
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def cond(pred: Expr, onT: Expr, onF: Expr) = if interpret(pred) != 0 then interpret(onT) else interpret(onF)
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def cond(pred: Expr, onT: Expr, onF: Expr) = if interpret(pred) then interpret(onT) else interpret(onF)
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def interpret(expr: Expr): Int = expr match case Num(value) => value case Add(lhs, rhs) => add(lhs, rhs) case Cond(pred, onT, onF) => cond(pred, onT, onF)
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
enum Value:
enum Value: case Num(value: Int)
enum Value: case Num(value: Int) case Bool(value: Boolean)
def interpret(expr: Expr): Int = expr match case Num(value) => value case Add(lhs, rhs) => add(lhs, rhs) case Cond(pred, onT, onF) => cond(pred, onT, onF)
def interpret(expr: Expr): Value = expr match case Num(value) => value case Add(lhs, rhs) => add(lhs, rhs) case Cond(pred, onT, onF) => cond(pred, onT, onF)
def interpret(expr: Expr): Value = expr match case Num(value) => value case Add(lhs, rhs) => add(lhs, rhs) case Cond(pred, onT, onF) => cond(pred, onT, onF)
Num value ⇓ value
def interpret(expr: Expr): Value = expr match case Num(value) => value case Add(lhs, rhs) => add(lhs, rhs) case Cond(pred, onT, onF) => cond(pred, onT, onF)
Num value ⇓ value
def interpret(expr: Expr): Value = expr match case Num(value) => Value.Num(value) case Add(lhs, rhs) => add(lhs, rhs) case Cond(pred, onT, onF) => cond(pred, onT, onF)
Num value ⇓ Value.Num value
def add(lhs: Expr, rhs: Expr) = val v1 = interpret(lhs) val v2 = interpret(rhs) v1 + v2
lhs ⇓ v₁ rhs ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Add lhs rhs ⇓ v₁ + v₂
def add(lhs: Expr, rhs: Expr) = val v1 = interpret(lhs) val v2 = interpret(rhs) v1 + v2
lhs ⇓ v₁ rhs ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Add lhs rhs ⇓ v₁ + v₂
def add(lhs: Expr, rhs: Expr) = val v1 = interpret(lhs) val v2 = interpret(rhs) v1 + v2
lhs ⇓ Value.Num v₁ rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs ⇓ v₁ + v₂
def add(lhs: Expr, rhs: Expr) = val v1 = interpret(lhs) val v2 = interpret(rhs) v1 + v2
lhs ⇓ Value.Num v₁ rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs ⇓ v₁ + v₂
def add(lhs: Expr, rhs: Expr) = val v1 = interpret(lhs) val v2 = interpret(rhs) v1 + v2
lhs ⇓ Value.Num v₁ rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs ⇓ Value.Num (v₁ + v₂)
def add(lhs: Expr, rhs: Expr) = val v1 = interpret(lhs) val v2 = interpret(rhs) v1 + v2
lhs ⇓ Value.Num v₁ rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs ⇓ Value.Num (v₁ + v₂)
def add(lhs: Expr, rhs: Expr) = val v1 = interpret(lhs) val v2 = interpret(rhs) v1 + v2
lhs ⇓ Value.Num v₁ rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs ⇓ Value.Num (v₁ + v₂)
def add(lhs: Expr, rhs: Expr) = (interpret(lhs), interpret(rhs)) match case (Value.Num(v1), Value.Num(v2)) =>
lhs ⇓ Value.Num v₁ rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs ⇓ Value.Num (v₁ + v₂)
def add(lhs: Expr, rhs: Expr) = (interpret(lhs), interpret(rhs)) match case (Value.Num(v1), Value.Num(v2)) =>
lhs ⇓ Value.Num v₁ rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs ⇓ Value.Num (v₁ + v₂)
def add(lhs: Expr, rhs: Expr) = (interpret(lhs), interpret(rhs)) match case (Value.Num(v1), Value.Num(v2)) =>
lhs ⇓ Value.Num v₁ rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs ⇓ Value.Num (v₁ + v₂)
def add(lhs: Expr, rhs: Expr) = (interpret(lhs), interpret(rhs)) match case (Value.Num(v1), Value.Num(v2)) => Value.Num(v1 + v2)
lhs ⇓ Value.Num v₁ rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs ⇓ Value.Num (v₁ + v₂)
def add(lhs: Expr, rhs: Expr) = (interpret(lhs), interpret(rhs)) match case (Value.Num(v1), Value.Num(v2)) => Value.Num(v1 + v2) case _ =>
lhs ⇓ Value.Num v₁ rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs ⇓ Value.Num (v₁ + v₂)
def add(lhs: Expr, rhs: Expr) = (interpret(lhs), interpret(rhs)) match case (Value.Num(v1), Value.Num(v2)) => Value.Num(v1 + v2) case _ => typeError("add")
lhs ⇓ Value.Num v₁ rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs ⇓ Value.Num (v₁ + v₂)
def cond(pred: Expr, onT: Expr, onF: Expr) = if interpret(pred) then interpret(onT) else interpret(onF)
pred ⇓ true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def cond(pred: Expr, onT: Expr, onF: Expr) = if interpret(pred) then interpret(onT) else interpret(onF)
pred ⇓ Value.Bool true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ Value.Bool false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def cond(pred: Expr, onT: Expr, onF: Expr) = if interpret(pred) then interpret(onT) else interpret(onF)
pred ⇓ Value.Bool true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ Value.Bool false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def cond(pred: Expr, onT: Expr, onF: Expr) = if interpret(pred) then interpret(onT) else interpret(onF)
pred ⇓ Value.Bool true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ Value.Bool false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def cond(pred: Expr, onT: Expr, onF: Expr) = if interpret(pred) then interpret(onT) else interpret(onF)
pred ⇓ Value.Bool true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ Value.Bool false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def cond(pred: Expr, onT: Expr, onF: Expr) = interpret(pred) match
pred ⇓ Value.Bool true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ Value.Bool false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def cond(pred: Expr, onT: Expr, onF: Expr) = interpret(pred) match case Value.Bool(true) =>
pred ⇓ Value.Bool true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ Value.Bool false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def cond(pred: Expr, onT: Expr, onF: Expr) = interpret(pred) match case Value.Bool(true) => interpret(onT)
pred ⇓ Value.Bool true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ Value.Bool false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def cond(pred: Expr, onT: Expr, onF: Expr) = interpret(pred) match case Value.Bool(true) => interpret(onT) case Value.Bool(false) =>
pred ⇓ Value.Bool true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ Value.Bool false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def cond(pred: Expr, onT: Expr, onF: Expr) = interpret(pred) match case Value.Bool(true) => interpret(onT) case Value.Bool(false) => interpret(onF)
pred ⇓ Value.Bool true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ Value.Bool false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def cond(pred: Expr, onT: Expr, onF: Expr) = interpret(pred) match case Value.Bool(true) => interpret(onT) case Value.Bool(false) => interpret(onF) case _ =>
pred ⇓ Value.Bool true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ Value.Bool false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
def cond(pred: Expr, onT: Expr, onF: Expr) = interpret(pred) match case Value.Bool(true) => interpret(onT) case Value.Bool(false) => interpret(onF) case _ => typeError("cond")
pred ⇓ Value.Bool true onT ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ vpred ⇓ Value.Bool false onF ⇓ v⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF ⇓ v
if true then 1 else 2
if true then 1 else 2
if true then 1 else 2
Bool ⇓ ???
if true then 1 else 2
Bool value ⇓ ???
if true then 1 else 2
Bool value ⇓ ???
if true then 1 else 2
Bool value ⇓ Value.Bool value
enum Expr: case Num(value: Int) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr)
Bool value ⇓ Value.Bool value
enum Expr: case Num(value: Int) case Bool() case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr)
Bool value ⇓ Value.Bool value
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr)
Bool value ⇓ Value.Bool value
def interpret(expr: Expr): Value = expr match case Num(value) => Value.Num(value) case Add(lhs, rhs) => add(lhs, rhs) case Cond(pred, onT, onF) => cond(pred, onT, onF)
Bool value ⇓ Value.Bool value
def interpret(expr: Expr): Value = expr match case Num(value) => Value.Num(value) case Bool(value) => case Add(lhs, rhs) => add(lhs, rhs) case Cond(pred, onT, onF) => cond(pred, onT, onF)
Bool value ⇓ Value.Bool value
def interpret(expr: Expr): Value = expr match case Num(value) => Value.Num(value) case Bool(value) => Value.Bool(value) case Add(lhs, rhs) => add(lhs, rhs) case Cond(pred, onT, onF) => cond(pred, onT, onF)
Bool value ⇓ Value.Bool value
if true then 1 else 2
val expr = Cond( pred = Bool(true), onT = Num(1), onF = Num(2))
interpret(expr)
if true then 1 else 2
val expr = Cond( pred = Bool(true), onT = Num(1), onF = Num(2))
interpret(expr)
if true then 1 else 2
val expr = Cond( pred = Bool(true), onT = Num(1), onF = Num(2))
interpret(expr)
if true then 1 else 2
val expr = Cond( pred = Bool(true), onT = Num(1), onF = Num(2))
interpret(expr)
if true then 1 else 2
val expr = Cond( pred = Bool(true), onT = Num(1), onF = Num(2))
interpret(expr)
if true then 1 else 2
val expr = Cond( pred = Bool(true), onT = Num(1), onF = Num(2))
interpret(expr)// val res2: Value = Num(1)
Conditionals are straightforward to support
They forced us to support multiple types of values
Conditionals are straightforward to support
They forced us to support multiple types of values
Friends don't let friends implement truthiness
let x = 1x
let x = 1x
xlet x = 1
let x = 1 in x + 2
let x = 1 in x + 2
x = 1
let x = 1 in x + 2
x = 1
let x = 1 in x + 2
x = 1
let x = 1 in x + 2
x = 1
let x = 1 in 1 + 2
x = 1
let x = 1 in 1 + 2
x = 1
let x = 1 in 3
x = 1
let x = 1 in 3
x = 1
3
let x = 1 + 2 in if true then 1 else x
let x = 1 + 2 in if true then 1 else x
let x = 1 + 2 in if true then 1 else x
let x = 1 + 2 in if true then 1 else x
let x = 1 + 2 in if true then 1 else x
let x = 1 + 2 in if true then 1 else x
let x = 3 in if true then 1 else x
let x = 3 in if true then 1 else x
x = 3
let x = 3 in if true then 1 else x
let x = 1 in x + (let x = 2 in x)
let x = 1 in x + (let x = 2 in x)
let x = 1 in x + (let x = 2 in x)
let x = 1 in x + (let x = 2 in x)
let x = 1 in x + (let x = 2 in x)
let x = 1 in x + (let x = 2 in x)
let x = 1 in (let x = 2 in x) + x
let x = 1 in (let x = 2 in x) + x
x = 1
let x = 1 in (let x = 2 in x) + x
x = 1
let x = 1 in (let x = 2 in x) + x
x = 1
let x = 1 in (let x = 2 in x) + x
x = 2
let x = 1 in (let x = 2 in x) + x
x = 2
let x = 1 in (let x = 2 in x) + x
x = 2
let x = 1 in (let x = 2 in 2) + x
x = 2
let x = 1 in (let x = 2 in 2) + x
x = 2
let x = 1 in 2 + x
x = 2
let x = 1 in 2 + x
x = 2
let x = 1 in 2 + 2
x = 2
let x = 1 in 2 + 2
x = 2
let x = 1 in 4
x = 1
let x = 1 in (let x = 2 in x) + x
x = 1x = 2
let x = 1 in (let x = 2 in x) + x
x = 1x = 2
let x = 1 in (let x = 2 in x) + x
x = 1x = 2
let x = 1 in (let x = 2 in 2) + x
x = 1x = 2
let x = 1 in (let x = 2 in 2) + x
x = 1
let x = 1 in 2 + x
x = 1
let x = 1 in 2 + x
x = 1
let x = 1 in 2 + 1
x = 1
let x = 1 in 2 + 1
x = 1
let x = 1 in 3
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Let ⇓ ???
let x = 1 in x + 2
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Let name ⇓ ???
let x = 1 in x + 2
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Let name value ⇓ ???
let x = 1 in x + 2
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Let name value body ⇓ ???
let x = 1 in x + 2
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Let name value body ⇓ ???
let x = 1 in x + 2
value ⇓ v₁⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Let name value body ⇓ ???
let x = 1 in x + 2
value ⇓ v₁⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Let name value body ⇓ ???
let x = 1 in x + 2
e |- value ⇓ v₁⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ ???
let x = 1 in x + 2
e |- value ⇓ v₁⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ ???
let x = 1 in x + 2
e |- value ⇓ v₁ ??? |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ ???
let x = 1 in x + 2
e |- value ⇓ v₁ ??? |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ ???
let x = 1 in x + 2
e |- value ⇓ v₁ e[name <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ ???
let x = 1 in x + 2
e |- value ⇓ v₁ e[name <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ ???
let x = 1 in x + 2
e |- value ⇓ v₁ e[name <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ v₂
let x = 1 in x + 2
e |- value ⇓ v₁ e[name <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ v₂
let x = 1 in x + 2
e |- value ⇓ v₁ e[name <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ v₂
let x = 1 in x + 2
e |- Ref ⇓ ???
let x = 1 in x + 2
e |- Ref name ⇓ ???
let x = 1 in x + 2
e |- Ref name ⇓ ???
let x = 1 in x + 2
e |- Ref name ⇓ e(name)
let x = 1 in x + 2
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr)
e |- value ⇓ v₁ e[name <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ v₂
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let()
e |- value ⇓ v₁ e[name <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ v₂
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String)
e |- value ⇓ v₁ e[name <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ v₂
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr)
e |- value ⇓ v₁ e[name <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ v₂
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr)
e |- value ⇓ v₁ e[name <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ v₂
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr)
e |- Ref name ⇓ e(name)
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case Ref()
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯e |- Ref name ⇓ e(name)
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case Ref(name: String)
e |- Ref name ⇓ e(name)
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case Ref(name: String)
e |- Ref name ⇓ e(name)
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case Ref(name: String)
e |- Ref name ⇓ e(name)
case class Env():
case class Env(env: List[Env.Binding]):
case class Env(env: List[Env.Binding]):object Env: case class Binding()
case class Env(env: List[Env.Binding]):object Env: case class Binding(name: String)
case class Env(env: List[Env.Binding]):object Env: case class Binding(name: String, value: Value)
case class Env(env: List[Env.Binding]): def lookup(name: String) =object Env: case class Binding(name: String, value: Value)
e |- Ref name ⇓ e(name)
case class Env(env: List[Env.Binding]): def lookup(name: String) = env.find(_.name == name)object Env: case class Binding(name: String, value: Value)
e |- Ref name ⇓ e(name)
case class Env(env: List[Env.Binding]): def lookup(name: String) = env.find(_.name == name) .map(_.value)object Env: case class Binding(name: String, value: Value)
e |- Ref name ⇓ e(name)
case class Env(env: List[Env.Binding]): def lookup(name: String) = env.find(_.name == name) .map(_.value) .getOrElse(sys.error(s"Unbound variable: $name"))object Env: case class Binding(name: String, value: Value)
e |- Ref name ⇓ e(name)
case class Env(env: List[Env.Binding]): def lookup(name: String) = env.find(_.name == name) .map(_.value) .getOrElse(sys.error(s"Unbound variable: $name")) def bind(name: String, value: Value) =object Env: case class Binding(name: String, value: Value)
e |- value ⇓ v₁ e[name <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ v₂
case class Env(env: List[Env.Binding]): def lookup(name: String) = env.find(_.name == name) .map(_.value) .getOrElse(sys.error(s"Unbound variable: $name")) def bind(name: String, value: Value) = Env.Binding(name, value)object Env: case class Binding(name: String, value: Value)
e |- value ⇓ v₁ e[name <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ v₂
case class Env(env: List[Env.Binding]): def lookup(name: String) = env.find(_.name == name) .map(_.value) .getOrElse(sys.error(s"Unbound variable: $name")) def bind(name: String, value: Value) = Env.Binding(name, value) :: envobject Env: case class Binding(name: String, value: Value)
e |- value ⇓ v₁ e[name <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ v₂
case class Env(env: List[Env.Binding]): def lookup(name: String) = env.find(_.name == name) .map(_.value) .getOrElse(sys.error(s"Unbound variable: $name")) def bind(name: String, value: Value) = Env(Env.Binding(name, value) :: env)object Env: case class Binding(name: String, value: Value)
e |- value ⇓ v₁ e[name <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ v₂
case class Env(env: List[Env.Binding]): def lookup(name: String) = env.find(_.name == name) .map(_.value) .getOrElse(sys.error(s"Unbound variable: $name")) def bind(name: String, value: Value) = Env(Env.Binding(name, value) :: env)object Env: case class Binding(name: String, value: Value) val empty = Env(List.empty)
def interpret(expr: Expr): Value = expr match case Num(value) => Value.Num(value) case Bool(value) => Value.Bool(value) case Add(lhs, rhs) => add(lhs, rhs) case Cond(pred, onT, onF) => cond(pred, onT, onF)
def interpret(expr: Expr, e: Env): Value = expr match case Num(value) => Value.Num(value) case Bool(value) => Value.Bool(value) case Add(lhs, rhs) => add(lhs, rhs, e) case Cond(pred, onT, onF) => cond(pred, onT, onF, e)
def interpret(expr: Expr, e: Env): Value = expr match case Num(value) => Value.Num(value) case Bool(value) => Value.Bool(value) case Add(lhs, rhs) => add(lhs, rhs, e) case Cond(pred, onT, onF) => cond(pred, onT, onF, e) case Let(name, value, body) => let(name, value, body, e)
e |- value ⇓ v₁ e[name <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ v₂
def let(name: String, value: Expr, body: Expr, e: Env) =
e |- value ⇓ v₁ e[name <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ v₂
def let(name: String, value: Expr, body: Expr, e: Env) = val v1 = interpret(value, e)
e |- value ⇓ v₁ e[name <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ v₂
def let(name: String, value: Expr, body: Expr, e: Env) = val v1 = interpret(value, e) val v2 = interpret(body, ???)
e |- value ⇓ v₁ e[name <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ v₂
def let(name: String, value: Expr, body: Expr, e: Env) = val v1 = interpret(value, e) val v2 = interpret(body, ???)
e |- value ⇓ v₁ e[name <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ v₂
def let(name: String, value: Expr, body: Expr, e: Env) = val v1 = interpret(value, e) val v2 = interpret(body, e.bind(name, v1))
e |- value ⇓ v₁ e[name <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ v₂
def let(name: String, value: Expr, body: Expr, e: Env) = val v1 = interpret(value, e) val v2 = interpret(body, e.bind(name, v1)) v2
e |- value ⇓ v₁ e[name <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Let name value body ⇓ v₂
def interpret(expr: Expr, e: Env): Value = expr match case Num(value) => Value.Num(value) case Bool(value) => Value.Bool(value) case Add(lhs, rhs) => add(lhs, rhs, e) case Cond(pred, onT, onF) => cond(pred, onT, onF, e) case Let(name, value, body) => let(name, value, body, e)
e |- Ref name ⇓ e(name)
def interpret(expr: Expr, e: Env): Value = expr match case Num(value) => Value.Num(value) case Bool(value) => Value.Bool(value) case Add(lhs, rhs) => add(lhs, rhs, e) case Cond(pred, onT, onF) => cond(pred, onT, onF, e) case Let(name, value, body) => let(name, value, body, e) case Ref(name) =>
e |- Ref name ⇓ e(name)
def interpret(expr: Expr, e: Env): Value = expr match case Num(value) => Value.Num(value) case Bool(value) => Value.Bool(value) case Add(lhs, rhs) => add(lhs, rhs, e) case Cond(pred, onT, onF) => cond(pred, onT, onF, e) case Let(name, value, body) => let(name, value, body, e) case Ref(name) => e.lookup(name)
e |- Ref name ⇓ e(name)
let x = 1 in (let x = 2 in x) + x
val expr = Let( // ...)
interpret(expr, Env.empty)
let x = 1 in (let x = 2 in x) + x
val expr = Let( // ...)
interpret(expr, Env.empty)// val res3: Value = Num(3)
Local bindings have a scope that can be analyzed statically
They can shadowed, but not overwritten
Local bindings have a scope that can be analyzed statically
They can shadowed, but not overwritten
Their interpretation requires an environment
let x = 1 in x + 2
let x = 1 in x + 2
let x = 1 in x + 2
let x = 1 in x + 2
(x -> x + 2) 1
(x -> x + 2) 1
(x -> x + 2) 1
(x -> x + 2) 1
x = 1
x + 2
x = 1
x + 2
x = 1
1 + 2
x = 1
1 + 2
x = 1
3
let f = x -> x + 2 in f 1
let f = x -> x + 2 in f 1
let f = x -> x + 2 in f 1
let f = x -> x + 2 in f 1
enum Value: case Num(value: Int) case Bool(value: Boolean)
let f = x -> x + 2 in f 1
enum Value: case Num(value: Int) case Bool(value: Boolean) case Fun()
let f = x -> x + 2 in f 1
enum Value: case Num(value: Int) case Bool(value: Boolean) case Fun(param: String)
let f = x -> x + 2 in f 1
enum Value: case Num(value: Int) case Bool(value: Boolean) case Fun(param: String, body: Expr)
let f = x -> x + 2 in f 1
let y = 1 in let f = x -> x + y in let y = 2 in f 3
let y = 1 in let f = x -> x + y in let y = 2 in f 3
let y = 1 in let f = x -> x + y in let y = 2 in f 3
let y = 1 in let f = x -> x + y in let y = 2 in f 3
let y = 1 in let f = x -> x + y in let y = 2 in f 3
y = 1
let y = 1 in let f = x -> x + y in let y = 2 in f 3
y = 1
let y = 1 in let f = x -> x + y in let y = 2 in f 3
y = 1f = x -> x + y
let y = 1 in let f = x -> x + y in let y = 2 in f 3
y = 1f = x -> x + y
let y = 1 in let f = x -> x + y in let y = 2 in f 3
y = 1f = x -> x + yy = 2
let y = 1 in let f = x -> x + y in let y = 2 in f 3
y = 1f = x -> x + yy = 2
let y = 1 in let f = x -> x + y in let y = 2 in f 3
y = 1f = x -> x + yy = 2x = 3
let y = 1 in let f = x -> x + y in let y = 2 in x + y
y = 1f = x -> x + yy = 2x = 3
let y = 1 in let f = x -> x + y in let y = 2 in x + y
y = 1f = x -> x + yy = 2
let y = 1 in let f = x -> x + y in let y = 2 in 3 + y
y = 1f = x -> x + yy = 2
let y = 1 in let f = x -> x + y in let y = 2 in 3 + y
y = 1f = x -> x + yy = 2
let y = 1 in let f = x -> x + y in let y = 2 in 3 + 2
y = 1f = x -> x + yy = 2
let y = 1 in let f = x -> x + y in let y = 2 in 3 + 2
y = 1f = x -> x + yy = 2
let y = 1 in let f = x -> x + y in let y = 2 in 5
y = 1f = x -> x + yy = 2x = 3
let y = 1 in let f = x -> x + y in let y = 2 in f 3
y = 1f = x -> x + yy = 2x = 3
let y = 1 in let f = x -> x + y in let y = 2 in f 3
y = 1f = x -> x + yy = 2x = 3
let y = 1 in let f = x -> x + y in let y = 2 in f 3
y = 1f = x -> x + yy = 2x = 3
let y = 1 in let f = x -> x + y in let y = 2 in f 3
enum Value: case Num(value: Int) case Bool(value: Boolean) case Fun(param: String, body: Expr)
enum Value: case Num(value: Int) case Bool(value: Boolean) case Fun(param: String, body: Expr, env: Env)
e |- Fun ⇓ ???
let f = x -> x + 2 in f 1
e |- Fun param ⇓ ???
let f = x -> x + 2 in f 1
e |- Fun param body ⇓ ???
let f = x -> x + 2 in f 1
e |- Fun param body ⇓ ???
let f = x -> x + 2 in f 1
e |- Fun param body ⇓ Value.Fun
let f = x -> x + 2 in f 1
e |- Fun param body ⇓ Value.Fun param
let f = x -> x + 2 in f 1
e |- Fun param body ⇓ Value.Fun param body
let f = x -> x + 2 in f 1
e |- Fun param body ⇓ Value.Fun param body e
let f = x -> x + 2 in f 1
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply ⇓ ???
let f = x -> x + 2 in f 1
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun ⇓ ???
let f = x -> x + 2 in f 1
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ ???
let f = x -> x + 2 in f 1
e |- fun ⇓ ???⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ ???
let f = x -> x + 2 in f 1
e |- fun ⇓ ???⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ ???
let f = x -> x + 2 in f 1
e |- fun ⇓ Value.Fun param body eʹ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ ???
let f = x -> x + 2 in f 1
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ ???
let f = x -> x + 2 in f 1
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁??? |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ ???
let f = x -> x + 2 in f 1
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁??? |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ ???
let f = x -> x + 2 in f 1
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ ???
let f = x -> x + 2 in f 1
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ ???
let f = x -> x + 2 in f 1
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ ???
let f = x -> x + 2 in f 1
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ ???
let f = x -> x + 2 in f 1
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁eʹ[param <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ ???
let f = x -> x + 2 in f 1
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁eʹ[param <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ ???
let f = x -> x + 2 in f 1
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁eʹ[param <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ v₂
let f = x -> x + 2 in f 1
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case Ref(name: String)
e |- Fun param body ⇓ Value.Fun param body e
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case Ref(name: String) case Fun()
e |- Fun param body ⇓ Value.Fun param body e
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case Ref(name: String) case Fun(param: String)
e |- Fun param body ⇓ Value.Fun param body e
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case Ref(name: String) case Fun(param: String, body: Expr)
e |- Fun param body ⇓ Value.Fun param body e
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case Ref(name: String) case Fun(param: String, body: Expr)
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁eʹ[param <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ v₂
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case Ref(name: String) case Fun(param: String, body: Expr) case Apply()
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁eʹ[param <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ v₂
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case Ref(name: String) case Fun(param: String, body: Expr) case Apply(fun: Expr)
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁eʹ[param <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ v₂
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case Ref(name: String) case Fun(param: String, body: Expr) case Apply(fun: Expr, arg: Expr)
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁eʹ[param <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ v₂
def interpret(expr: Expr, e: Env): Value = expr match case Num(value) => Value.Num(value) case Bool(value) => Value.Bool(value) case Add(lhs, rhs) => add(lhs, rhs, e) case Cond(pred, onT, onF) => cond(pred, onT, onF, e) case Let(name, value, body) => let(name, value, body, e) case Ref(name) => e.lookup(name)
e |- Fun param body ⇓ Value.Fun param body e
def interpret(expr: Expr, e: Env): Value = expr match case Num(value) => Value.Num(value) case Bool(value) => Value.Bool(value) case Add(lhs, rhs) => add(lhs, rhs, e) case Cond(pred, onT, onF) => cond(pred, onT, onF, e) case Let(name, value, body) => let(name, value, body, e) case Ref(name) => e.lookup(name) case Fun(param, body) => Value.Fun(param, body, e)
e |- Fun param body ⇓ Value.Fun param body e
def interpret(expr: Expr, e: Env): Value = expr match case Num(value) => Value.Num(value) case Bool(value) => Value.Bool(value) case Add(lhs, rhs) => add(lhs, rhs, e) case Cond(pred, onT, onF) => cond(pred, onT, onF, e) case Let(name, value, body) => let(name, value, body, e) case Ref(name) => e.lookup(name) case Fun(param, body) => Value.Fun(param, body, e)
e |- Fun param body ⇓ Value.Fun param body e
def interpret(expr: Expr, e: Env): Value = expr match case Num(value) => Value.Num(value) case Bool(value) => Value.Bool(value) case Add(lhs, rhs) => add(lhs, rhs, e) case Cond(pred, onT, onF) => cond(pred, onT, onF, e) case Let(name, value, body) => let(name, value, body, e) case Ref(name) => e.lookup(name) case Fun(param, body) => Value.Fun(param, body, e)
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁eʹ[param <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ v₂
def interpret(expr: Expr, e: Env): Value = expr match case Num(value) => Value.Num(value) case Bool(value) => Value.Bool(value) case Add(lhs, rhs) => add(lhs, rhs, e) case Cond(pred, onT, onF) => cond(pred, onT, onF, e) case Let(name, value, body) => let(name, value, body, e) case Ref(name) => e.lookup(name) case Fun(param, body) => Value.Fun(param, body, e) case Apply(fun, arg) => apply(fun, arg, e)
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁eʹ[param <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ v₂
def apply(fun: Expr, arg: Expr, e: Env) =
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁eʹ[param <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ v₂
def apply(fun: Expr, arg: Expr, e: Env) = interpret(fun, e) match case Value.Fun(param, body, eʹ) =>
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁eʹ[param <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ v₂
def apply(fun: Expr, arg: Expr, e: Env) = interpret(fun, e) match case Value.Fun(param, body, eʹ) => val v1 = interpret(arg, e)
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁eʹ[param <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ v₂
def apply(fun: Expr, arg: Expr, e: Env) = interpret(fun, e) match case Value.Fun(param, body, eʹ) => val v1 = interpret(arg, e) val v2 = interpret(body, ???)
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁eʹ[param <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ v₂
def apply(fun: Expr, arg: Expr, e: Env) = interpret(fun, e) match case Value.Fun(param, body, eʹ) => val v1 = interpret(arg, e) val v2 = interpret(body, ???)
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁eʹ[param <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ v₂
def apply(fun: Expr, arg: Expr, e: Env) = interpret(fun, e) match case Value.Fun(param, body, eʹ) => val v1 = interpret(arg, e) val v2 = interpret(body, eʹ.bind(param, v1))
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁eʹ[param <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ v₂
def apply(fun: Expr, arg: Expr, e: Env) = interpret(fun, e) match case Value.Fun(param, body, eʹ) => val v1 = interpret(arg, e) val v2 = interpret(body, eʹ.bind(param, v1)) v2
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁eʹ[param <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ v₂
def apply(fun: Expr, arg: Expr, e: Env) = interpret(fun, e) match case Value.Fun(param, body, eʹ) => val v1 = interpret(arg, e) val v2 = interpret(body, eʹ.bind(param, v1)) v2 case _ => typeError("apply")
e |- fun ⇓ Value.Fun param body eʹ e |- arg ⇓ v₁eʹ[param <- v₁] |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Apply fun arg ⇓ v₂
let y = 1 in let f = x -> x + y in let y = 2 in f 3
val expr = Let( // ...)
interpret(expr, Env.empty)
let y = 1 in let f = x -> x + y in let y = 2 in f 3
val expr = Let( // ...)
interpret(expr, Env.empty)// val res4: Value = Num(4)
let add = ??? in add 1 2
val expr = ???
interpret(expr, Env.empty)
let add = ??? in add 1 2
val expr = ???
interpret(expr, Env.empty)
let add = lhs -> ??? in add 1 2
val expr = ???
interpret(expr, Env.empty)
let add = lhs -> ??? in add 1 2
val expr = ???
interpret(expr, Env.empty)
let add = lhs -> rhs -> ??? in add 1 2
val expr = ???
interpret(expr, Env.empty)
let add = lhs -> rhs -> ??? in add 1 2
val expr = ???
interpret(expr, Env.empty)
let add = lhs -> rhs -> lhs + rhs in add 1 2
val expr = ???
interpret(expr, Env.empty)
let add = lhs -> rhs -> lhs + rhs in add 1 2
val expr = ???
interpret(expr, Env.empty)
let add = lhs -> rhs -> lhs + rhs in add 1 2
val expr = Let( // ...)
interpret(expr, Env.empty)
let add = lhs -> rhs -> lhs + rhs in add 1 2
val expr = Let( // ...)
interpret(expr, Env.empty)// val res5: Value = Num(3)
Functions are values
They close over their environment
Yes, unary functions are sufficient
let sumFor = lower -> upper -> var acc = 0 for i = lower to upper do acc = acc + i acc in sumFor 1 10
let sumFor = lower -> upper -> var acc = 0 for i = lower to upper do acc = acc + i acc in sumFor 1 10
let sumFor = lower -> upper -> var acc = 0 for i = lower to upper do acc = acc + i acc in sumFor 1 10
let sumFor = lower -> upper -> var acc = 0 for i = lower to upper do acc = acc + i acc in sumFor 1 10
let sumFor = lower -> upper -> var acc = 0 for i = lower to upper do acc = acc + i acc in sumFor 1 10
let sumFor = lower -> upper -> var acc = 0 for i = lower to upper do acc = acc + i acc in sumFor 1 10
let sumFor = lower -> upper -> var acc = 0 for i = lower to upper do acc = acc + i acc in sumFor 1 10
let sumWhile = lower -> upper -> var acc = 0 for i = lower to upper do acc = acc + i acc in sumWhile 1 10
let sumWhile = lower -> upper -> var acc = 0 for i = lower to upper do acc = acc + i acc in sumWhile 1 10
let sumWhile = lower -> upper -> var acc = 0 var i = lower for i = lower to upper do acc = acc + i acc in sumWhile 1 10
let sumWhile = lower -> upper -> var acc = 0 var i = lower for i = lower to upper do acc = acc + i i = i + 1 acc in sumWhile 1 10
let sumWhile = lower -> upper -> var acc = 0 var i = lower for i = lower to upper do acc = acc + i i = i + 1 acc in sumWhile 1 10
let sumWhile = lower -> upper -> var acc = 0 var i = lower while i < upper do acc = acc + i i = i + 1 acc in sumWhile 1 10
let sumWhile = lower -> upper -> var acc = 0 var i = lower while i < upper do acc = acc + i i = i + 1 acc in sumWhile 1 10
let sumRec = lower -> upper -> var acc = 0 var i = lower while i < upper do acc = acc + i i = i + 1 acc in sumRec 1 10
let sumRec = lower -> upper -> var acc = 0 var i = lower while i < upper do acc = acc + i i = i + 1 acc in sumRec 1 10
let sumRec = lower -> upper -> var acc = 0 var i = lower while i < upper do acc = acc + i i = i + 1 acc in sumRec 1 10
let sumRec = lower -> upper -> let go = acc -> i -> while i < upper do acc = acc + i i = i + 1 acc in go 0 lower in sumRec 1 10
let sumRec = lower -> upper -> let go = acc -> i -> while i < upper do acc = acc + i i = i + 1 acc in go 0 lower in sumRec 1 10
let sumRec = lower -> upper -> let go = acc -> i -> if i < upper then go (acc + i) (i + 1) acc in go 0 lower in sumRec 1 10
let sumRec = lower -> upper -> let go = acc -> i -> if i < upper then go (acc + i) (i + 1) acc in go 0 lower in sumRec 1 10
let sumRec = lower -> upper -> let go = acc -> i -> if i < upper then go (acc + i) (i + 1) else acc in go 0 lower in sumRec 1 10
let sumRec = lower -> upper -> let go = acc -> i -> if i < upper then go (acc + i) (i + 1) else acc in go 0 lower in sumRec 1 10
let sum = lower -> upper -> let go = acc -> i -> if i < upper then go (acc + i) (i + 1) else acc in go 0 lower in sum 1 10
let sum = lower -> upper -> let go = acc -> i -> if i < upper then go (acc + i) (i + 1) else acc in go 0 lower in sum 1 10
let sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
let sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
let sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
let sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
let sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Gt ⇓ ???
if 1 > 2 then false else true
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Gt lhs ⇓ ???
if 1 > 2 then false else true
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Gt lhs rhs ⇓ ???
if 1 > 2 then false else true
e |- lhs ⇓ Value.Num v₁⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Gt lhs rhs ⇓ ???
if 1 > 2 then false else true
e |- lhs ⇓ Value.Num v₁ e |- rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Gt lhs rhs ⇓ ???
if 1 > 2 then false else true
e |- lhs ⇓ Value.Num v₁ e |- rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Gt lhs rhs ⇓ ???
if 1 > 2 then false else true
e |- lhs ⇓ Value.Num v₁ e |- rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Gt lhs rhs ⇓ Value.Bool (v₁ > v₂)
if 1 > 2 then false else true
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case Ref(name: String) case Fun(param: String, body: Expr) case Apply(fun: Expr, arg: Expr)
e |- lhs ⇓ Value.Num v₁ e |- rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Gt lhs rhs ⇓ Value.Bool (v₁ > v₂)
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Gt() case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case Ref(name: String) case Fun(param: String, body: Expr) case Apply(fun: Expr, arg: Expr)
e |- lhs ⇓ Value.Num v₁ e |- rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Gt lhs rhs ⇓ Value.Bool (v₁ > v₂)
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Gt(lhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case Ref(name: String) case Fun(param: String, body: Expr) case Apply(fun: Expr, arg: Expr)
e |- lhs ⇓ Value.Num v₁ e |- rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Gt lhs rhs ⇓ Value.Bool (v₁ > v₂)
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Gt(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case Ref(name: String) case Fun(param: String, body: Expr) case Apply(fun: Expr, arg: Expr)
e |- lhs ⇓ Value.Num v₁ e |- rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Gt lhs rhs ⇓ Value.Bool (v₁ > v₂)
def interpret(expr: Expr, e: Env): Value = expr match case Num(value) => Value.Num(value) case Bool(value) => Value.Bool(value) case Add(lhs, rhs) => add(lhs, rhs, e) case Cond(pred, onT, onF) => cond(pred, onT, onF, e) case Let(name, value, body) => let(name, value, body, e) case Ref(name) => e.lookup(name) case Fun(param, body) => Value.Fun(param, body, e) case Apply(fun, arg) => apply(fun, arg, e)
e |- lhs ⇓ Value.Num v₁ e |- rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Gt lhs rhs ⇓ Value.Bool (v₁ > v₂)
def interpret(expr: Expr, e: Env): Value = expr match case Num(value) => Value.Num(value) case Bool(value) => Value.Bool(value) case Add(lhs, rhs) => add(lhs, rhs, e) case Gt(lhs, rhs) => gt(lhs, rhs, e) case Cond(pred, onT, onF) => cond(pred, onT, onF, e) case Let(name, value, body) => let(name, value, body, e) case Ref(name) => e.lookup(name) case Fun(param, body) => Value.Fun(param, body, e) case Apply(fun, arg) => apply(fun, arg, e)
e |- lhs ⇓ Value.Num v₁ e |- rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Gt lhs rhs ⇓ Value.Bool (v₁ > v₂)
def gt(lhs: Expr, rhs: Expr, e: Env) =
e |- lhs ⇓ Value.Num v₁ e |- rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Gt lhs rhs ⇓ Value.Bool (v₁ > v₂)
def gt(lhs: Expr, rhs: Expr, e: Env) = (interpret(lhs, e), interpret(rhs, e)) match case (Value.Num(v1), Value.Num(v2)) =>
e |- lhs ⇓ Value.Num v₁ e |- rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Gt lhs rhs ⇓ Value.Bool (v₁ > v₂)
def gt(lhs: Expr, rhs: Expr, e: Env) = (interpret(lhs, e), interpret(rhs, e)) match case (Value.Num(v1), Value.Num(v2)) =>
e |- lhs ⇓ Value.Num v₁ e |- rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Gt lhs rhs ⇓ Value.Bool (v₁ > v₂)
def gt(lhs: Expr, rhs: Expr, e: Env) = (interpret(lhs, e), interpret(rhs, e)) match case (Value.Num(v1), Value.Num(v2)) =>
e |- lhs ⇓ Value.Num v₁ e |- rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Gt lhs rhs ⇓ Value.Bool (v₁ > v₂)
def gt(lhs: Expr, rhs: Expr, e: Env) = (interpret(lhs, e), interpret(rhs, e)) match case (Value.Num(v1), Value.Num(v2)) => Value.Bool(v1 > v2)
e |- lhs ⇓ Value.Num v₁ e |- rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Gt lhs rhs ⇓ Value.Bool (v₁ > v₂)
def gt(lhs: Expr, rhs: Expr, e: Env) = (interpret(lhs, e), interpret(rhs, e)) match case (Value.Num(v1), Value.Num(v2)) => Value.Bool(v1 > v2) case _ =>
e |- lhs ⇓ Value.Num v₁ e |- rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Gt lhs rhs ⇓ Value.Bool (v₁ > v₂)
def gt(lhs: Expr, rhs: Expr, e: Env) = (interpret(lhs, e), interpret(rhs, e)) match case (Value.Num(v1), Value.Num(v2)) => Value.Bool(v1 > v2) case _ => typeError("gt")
e |- lhs ⇓ Value.Num v₁ e |- rhs ⇓ Value.Num v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- Gt lhs rhs ⇓ Value.Bool (v₁ > v₂)
let sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
val expr = Let( // ...)
interpret(expr, Env.empty)
let sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
val expr = Let( // ...)
interpret(expr, Env.empty)// ⛔ Unbound variable: sum
let sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
val expr = Let( // ...)
interpret(expr, Env.empty)// ⛔ Unbound variable: sum
let sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
val expr = Let( // ...)
interpret(expr, Env.empty)// ⛔ Unbound variable: sum
let sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
val expr = Let( // ...)
interpret(expr, Env.empty)// ⛔ Unbound variable: sum
let sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
let rec sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
enum Value: case Num(value: Int) case Bool(value: Boolean) case Fun(param: String, body: Expr, env: Env)
let rec sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
let rec sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec ⇓ ???
let rec sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name ⇓ ???
let rec sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value ⇓ ???
let rec sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ ???
let rec sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
e |- value ⇓ v₁⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ ???
let rec sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
e |- value ⇓ v₁⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ ???
let rec sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
eʹ = e[name <- ???]; e |- value ⇓ v₁⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ ???
let rec sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
eʹ = e[name <- ???]; e |- value ⇓ v₁⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ ???
let rec sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
eʹ = e[name <- ∅]; e |- value ⇓ v₁⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ ???
let rec sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
eʹ = e[name <- ∅]; e |- value ⇓ v₁⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ ???
let rec sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
eʹ = e[name <- ∅]; eʹ |- value ⇓ v₁⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ ???
let rec sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
eʹ = e[name <- ∅]; eʹ |- value ⇓ v₁ eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ ???
let rec sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
eʹ = e[name <- ∅]; eʹ |- value ⇓ v₁ eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ ???
let rec sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
eʹ = e[name <- ∅]; eʹ |- value ⇓ v₁ eʹ[name := v₁]; eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ ???
let rec sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
eʹ = e[name <- ∅]; eʹ |- value ⇓ v₁ eʹ[name := v₁]; eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ ???
let rec sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
eʹ = e[name <- ∅]; eʹ |- value ⇓ v₁ eʹ[name := v₁]; eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ v₂
let rec sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Gt(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case Ref(name: String) case Fun(param: String, body: Expr) case Apply(fun: Expr, arg: Expr)
eʹ = e[name <- ∅]; eʹ |- value ⇓ v₁ eʹ[name := v₁]; eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ v₂
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Gt(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case LetRec() case Ref(name: String) case Fun(param: String, body: Expr) case Apply(fun: Expr, arg: Expr)
eʹ = e[name <- ∅]; eʹ |- value ⇓ v₁ eʹ[name := v₁]; eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ v₂
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Gt(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case LetRec(name: String) case Ref(name: String) case Fun(param: String, body: Expr) case Apply(fun: Expr, arg: Expr)
eʹ = e[name <- ∅]; eʹ |- value ⇓ v₁ eʹ[name := v₁]; eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ v₂
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Gt(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case LetRec(name: String, value: Expr) case Ref(name: String) case Fun(param: String, body: Expr) case Apply(fun: Expr, arg: Expr)
eʹ = e[name <- ∅]; eʹ |- value ⇓ v₁ eʹ[name := v₁]; eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ v₂
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Gt(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case LetRec(name: String, value: Expr, body: Expr) case Ref(name: String) case Fun(param: String, body: Expr) case Apply(fun: Expr, arg: Expr)
eʹ = e[name <- ∅]; eʹ |- value ⇓ v₁ eʹ[name := v₁]; eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ v₂
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Gt(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case LetRec(name: String, value: Expr, body: Expr) case Ref(name: String) case Fun(param: String, body: Expr) case Apply(fun: Expr, arg: Expr)
eʹ = e[name <- ∅]; eʹ |- value ⇓ v₁ eʹ[name := v₁]; eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ v₂
case class Env(env: List[Env.Binding]): def lookup(name: String) = env.find(_.name == name) .map(_.value) .getOrElse(sys.error(s"Unbound variable: $name")) def bind(name: String, value: Value) = Env(Env.Binding(name, value) :: env)object Env: case class Binding(name: String, value: Value) val empty = Env(List.empty)
case class Env(env: List[Env.Binding]): def lookup(name: String) = env.find(_.name == name) .map(_.value) .getOrElse(sys.error(s"Unbound variable: $name")) def bind(name: String, value: Value) = Env(Env.Binding(name, value) :: env) def update(name: String, value: Value) =object Env: case class Binding(name: String, value: Value) val empty = Env(List.empty)
case class Env(env: List[Env.Binding]): def lookup(name: String) = env.find(_.name == name) .map(_.value) .getOrElse(sys.error(s"Unbound variable: $name")) def bind(name: String, value: Value) = Env(Env.Binding(name, value) :: env) def update(name: String, value: Value) = env.find(_.name == name)object Env: case class Binding(name: String, value: Value) val empty = Env(List.empty)
case class Env(env: List[Env.Binding]): def lookup(name: String) = env.find(_.name == name) .map(_.value) .getOrElse(sys.error(s"Unbound variable: $name")) def bind(name: String, value: Value) = Env(Env.Binding(name, value) :: env) def update(name: String, value: Value) = env.find(_.name == name) .foreach(_.value = value)object Env: case class Binding(name: String, value: Value) val empty = Env(List.empty)
case class Env(env: List[Env.Binding]): def lookup(name: String) = env.find(_.name == name) .map(_.value) .getOrElse(sys.error(s"Unbound variable: $name")) def bind(name: String, value: Value) = Env(Env.Binding(name, value) :: env) def update(name: String, value: Value) = env.find(_.name == name) .foreach(_.value = value)object Env: case class Binding(name: String, value: Value) val empty = Env(List.empty)
case class Env(env: List[Env.Binding]): def lookup(name: String) = env.find(_.name == name) .map(_.value) .getOrElse(sys.error(s"Unbound variable: $name")) def bind(name: String, value: Value) = Env(Env.Binding(name, value) :: env) def update(name: String, value: Value) = env.find(_.name == name) .foreach(_.value = value)object Env: case class Binding(name: String, var value: Value) val empty = Env(List.empty)
def interpret(expr: Expr, e: Env): Value = expr match case Num(value) => Value.Num(value) case Bool(value) => Value.Bool(value) case Add(lhs, rhs) => add(lhs, rhs, e) case Gt(lhs, rhs) => gt(lhs, rhs, e) case Cond(pred, onT, onF) => cond(pred, onT, onF, e) case Let(name, value, body) => let(name, value, body, e) case Ref(name) => e.lookup(name) case Fun(param, body) => Value.Fun(param, body, e) case Apply(fun, arg) => apply(fun, arg, e)
eʹ = e[name <- ∅]; eʹ |- value ⇓ v₁ eʹ[name := v₁]; eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ v₂
def interpret(expr: Expr, e: Env): Value = expr match case Num(value) => Value.Num(value) case Bool(value) => Value.Bool(value) case Add(lhs, rhs) => add(lhs, rhs, e) case Gt(lhs, rhs) => gt(lhs, rhs, e) case Cond(pred, onT, onF) => cond(pred, onT, onF, e) case Let(name, value, body) => let(name, value, body, e) case LetRec(name, value, body) => letRec(name, value, body, e) case Ref(name) => e.lookup(name) case Fun(param, body) => Value.Fun(param, body, e) case Apply(fun, arg) => apply(fun, arg, e)
eʹ = e[name <- ∅]; eʹ |- value ⇓ v₁ eʹ[name := v₁]; eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ v₂
def letRec(name: String, value: Expr, body: Expr, e: Env) =
eʹ = e[name <- ∅]; eʹ |- value ⇓ v₁ eʹ[name := v₁]; eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ v₂
def letRec(name: String, value: Expr, body: Expr, e: Env) = val eʹ = e.bind(name, null)
eʹ = e[name <- ∅]; eʹ |- value ⇓ v₁ eʹ[name := v₁]; eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ v₂
def letRec(name: String, value: Expr, body: Expr, e: Env) = val eʹ = e.bind(name, null) val v1 = interpret(value, eʹ)
eʹ = e[name <- ∅]; eʹ |- value ⇓ v₁ eʹ[name := v₁]; eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ v₂
def letRec(name: String, value: Expr, body: Expr, e: Env) = val eʹ = e.bind(name, null) val v1 = interpret(value, eʹ) eʹ.update(name, v1)
eʹ = e[name <- ∅]; eʹ |- value ⇓ v₁ eʹ[name := v₁]; eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ v₂
def letRec(name: String, value: Expr, body: Expr, e: Env) = val eʹ = e.bind(name, null) val v1 = interpret(value, eʹ) eʹ.update(name, v1) val v2 = interpret(body, eʹ)
eʹ = e[name <- ∅]; eʹ |- value ⇓ v₁ eʹ[name := v₁]; eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ v₂
def letRec(name: String, value: Expr, body: Expr, e: Env) = val eʹ = e.bind(name, null) val v1 = interpret(value, eʹ) eʹ.update(name, v1) val v2 = interpret(body, eʹ) v2
eʹ = e[name <- ∅]; eʹ |- value ⇓ v₁ eʹ[name := v₁]; eʹ |- body ⇓ v₂⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ e |- LetRec name value body ⇓ v₂
let sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
val expr = Let( // ...)
interpret(expr, Env.empty)
let sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
val expr = Let( // ...)
interpret(expr, Env.empty)
let rec sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
val expr = LetRec( // ...)
interpret(expr, Env.empty)
let rec sum = lower -> upper -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
val expr = LetRec( // ...)
interpret(expr, Env.empty)// val res6: Value = Num(55)
Loops are implemented as recursive functions
Recursive functions need special syntax...
Loops are implemented as recursive functions
Recursive functions need special syntax...
... and a mutable environment
1 + true
val expr = Add( Num(1), Bool(true))
interpret(expr, Env.empty)
1 + true
val expr = Add( Num(1), Bool(true))
interpret(expr, Env.empty)
1 + true
val expr = Add( Num(1), Bool(true))
interpret(expr, Env.empty)
1 + true
val expr = Add( Num(1), Bool(true))
interpret(expr, Env.empty)
1 + true
val expr = Add( Num(1), Bool(true))
interpret(expr, Env.empty)// ⛔ Type error in add
def typeCheck(expr: Expr): ??? =
def typeCheck(expr: Expr): ??? =
def typeCheck(expr: Expr): ??? =
def typeCheck(expr: Expr): Boolean =
def typeCheck(expr: Expr): Boolean = expr match case Num(value) => ???
def typeCheck(expr: Expr): Boolean = expr match case Num(value) => ???
def typeCheck(expr: Expr): Boolean = expr match case Num(value) => true
def typeCheck(expr: Expr): Boolean = expr match case Num(value) => true case Bool(value) => ???
def typeCheck(expr: Expr): Boolean = expr match case Num(value) => true case Bool(value) => ???
def typeCheck(expr: Expr): Boolean = expr match case Num(value) => true case Bool(value) => true
def typeCheck(expr: Expr): Boolean = expr match case Num(value) => true case Bool(value) => true case Add(lhs, rhs) => ???
def typeCheck(expr: Expr): Boolean = expr match case Num(value) => true case Bool(value) => true case Add(lhs, rhs) => ???
def typeCheck(expr: Expr): Boolean = expr match case Num(value) => true case Bool(value) => true case Add(lhs, rhs) => typeCheck(lhs) && typeCheck(rhs)
1 + true
val expr = Add( Num(1), Bool(true))
interpret(expr, Env.empty)
1 + true
val expr = Add( Num(1), Bool(true))
interpret(expr, Env.empty)
1 + true
val expr = Add( Num(1), Bool(true))
typeCheck(expr)
1 + true
val expr = Add( Num(1), Bool(true))
typeCheck(expr)// val res7: Boolean = true
def typeCheck(expr: Expr): Boolean = expr match case Num(value) => true case Bool(value) => true case Add(lhs, rhs) => typeCheck(lhs) && typeCheck(rhs)
def typeCheck(expr: Expr): Boolean = expr match case Num(value) => true case Bool(value) => true case Add(lhs, rhs) => typeCheck(lhs) && typeCheck(rhs)
enum Type:
enum Type: case Num
enum Type: case Num case Bool
def typeCheck(expr: Expr): Boolean = expr match case Num(value) => true case Bool(value) => true case Add(lhs, rhs) => typeCheck(lhs) && typeCheck(rhs)
def typeCheck(expr: Expr): Either[String, Type] = expr match case Num(value) => true case Bool(value) => true case Add(lhs, rhs) => typeCheck(lhs) && typeCheck(rhs)
def typeCheck(expr: Expr): Either[String, Type] = expr match case Num(value) => true case Bool(value) => true case Add(lhs, rhs) => typeCheck(lhs) && typeCheck(rhs)
Num value : ???
1
Num value : ???
1
Num value : ???
1
Num value : ???
1
Num value : Type.Num
1
def typeCheck(expr: Expr): Either[String, Type] = expr match case Num(value) => true case Bool(value) => true case Add(lhs, rhs) => typeCheck(lhs) && typeCheck(rhs)
Num value : Type.Num
def typeCheck(expr: Expr): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => true case Add(lhs, rhs) => typeCheck(lhs) && typeCheck(rhs)
Num value : Type.Num
def typeCheck(expr: Expr): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => true case Add(lhs, rhs) => typeCheck(lhs) && typeCheck(rhs)
Bool value : ???
true
Bool value : ???
true
Bool value : Type.Bool
true
def typeCheck(expr: Expr): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => true case Add(lhs, rhs) => typeCheck(lhs) && typeCheck(rhs)
Bool value : Type.Bool
def typeCheck(expr: Expr): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => typeCheck(lhs) && typeCheck(rhs)
Bool value : Type.Bool
def typeCheck(expr: Expr): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => typeCheck(lhs) && typeCheck(rhs)
Add lhs rhs : ???
1 + 2
lhs : Type.Num Add lhs rhs : ???
1 + 2
lhs : Type.Num rhs : Type.Num Add lhs rhs : ???
1 + 2
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs : ???
1 + 2
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs : ???
1 + 2
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs : Type.Num
1 + 2
def typeCheck(expr: Expr): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => typeCheck(lhs) && typeCheck(rhs)
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs : Type.Num
def typeCheck(expr: Expr): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs)
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs : Type.Num
def checkAdd(lhs: Expr, rhs: Expr) =
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs : Type.Num
def checkAdd(lhs: Expr, rhs: Expr) =
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs : Type.Num
def expect() =
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs : Type.Num
def expect(expr: Expr) =
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs : Type.Num
def expect(expr: Expr, expected: Type) =
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs : Type.Num
def expect(expr: Expr, expected: Type) = typeCheck(expr).flatMap =>
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs : Type.Num
def expect(expr: Expr, expected: Type) = typeCheck(expr).flatMap: observed =>
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs : Type.Num
def expect(expr: Expr, expected: Type) = typeCheck(expr).flatMap: observed => if observed == expected then
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs : Type.Num
def expect(expr: Expr, expected: Type) = typeCheck(expr).flatMap: observed => if observed == expected then Right(())
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs : Type.Num
def expect(expr: Expr, expected: Type) = typeCheck(expr).flatMap: observed => if observed == expected then Right(()) else Left(s"Expected $expected, found $observed")
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs : Type.Num
def checkAdd(lhs: Expr, rhs: Expr) =
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs : Type.Num
def checkAdd(lhs: Expr, rhs: Expr) = for _ <- expect(lhs, Type.Num)
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs : Type.Num
def checkAdd(lhs: Expr, rhs: Expr) = for _ <- expect(lhs, Type.Num) _ <- expect(rhs, Type.Num)
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs : Type.Num
def checkAdd(lhs: Expr, rhs: Expr) = for _ <- expect(lhs, Type.Num) _ <- expect(rhs, Type.Num) yield Type.Num
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Add lhs rhs : Type.Num
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Gt lhs rhs : ???
1 > 2
lhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Gt lhs rhs : ???
1 > 2
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Gt lhs rhs : ???
1 > 2
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Gt lhs rhs : ???
1 > 2
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Gt lhs rhs : Type.Bool
1 > 2
def typeCheck(expr: Expr): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs)
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Gt lhs rhs : Type.Bool
def typeCheck(expr: Expr): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs) case Gt(lhs, rhs) =>
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Gt lhs rhs : Type.Bool
def typeCheck(expr: Expr): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs) case Gt(lhs, rhs) => checkGt(lhs, rhs)
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Gt lhs rhs : Type.Bool
def checkGt(lhs: Expr, rhs: Expr) =
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Gt lhs rhs : Type.Bool
def checkGt(lhs: Expr, rhs: Expr) = for _ <- expect(lhs, Type.Num)
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Gt lhs rhs : Type.Bool
def checkGt(lhs: Expr, rhs: Expr) = for _ <- expect(lhs, Type.Num) _ <- expect(rhs, Type.Num)
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Gt lhs rhs : Type.Bool
def checkGt(lhs: Expr, rhs: Expr) = for _ <- expect(lhs, Type.Num) _ <- expect(rhs, Type.Num) yield Type.Bool
lhs : Type.Num rhs : Type.Num⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Gt lhs rhs : Type.Bool
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF : ???
if true then 1 else 2
pred : Type.Bool⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF : ???
if true then 1 else 2
pred : Type.Bool onT : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF : ???
if true then 1 else 2
pred : Type.Bool onT : X onF : ???⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF : ???
if true then 1 else 2
pred : Type.Bool onT : X onF : ???⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF : ???
if true then 1 else 2
pred : Type.Bool onT : X onF : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF : ???
if true then 1 else 2
pred : Type.Bool onT : X onF : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF : ???
if true then 1 else 2
pred : Type.Bool onT : X onF : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF : X
if true then 1 else 2
def typeCheck(expr: Expr): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs) case Gt(lhs, rhs) => checkGt(lhs, rhs)
pred : Type.Bool onT : X onF : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF : X
def typeCheck(expr: Expr): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs) case Gt(lhs, rhs) => checkGt(lhs, rhs) case Cond(pred, onT, onF) =>
pred : Type.Bool onT : X onF : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF : X
def typeCheck(expr: Expr): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs) case Gt(lhs, rhs) => checkGt(lhs, rhs) case Cond(pred, onT, onF) => checkCond(pred, onT, onF)
pred : Type.Bool onT : X onF : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF : X
def checkCond(pred: Expr, onT: Expr, onF: Expr) =
pred : Type.Bool onT : X onF : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF : X
def checkCond(pred: Expr, onT: Expr, onF: Expr) = for _ <- expect(pred, Type.Bool)
pred : Type.Bool onT : X onF : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF : X
def checkCond(pred: Expr, onT: Expr, onF: Expr) = for _ <- expect(pred, Type.Bool) x <- typeCheck(onT)
pred : Type.Bool onT : X onF : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF : X
def checkCond(pred: Expr, onT: Expr, onF: Expr) = for _ <- expect(pred, Type.Bool) x <- typeCheck(onT) _ <- expect(onF, x)
pred : Type.Bool onT : X onF : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF : X
def checkCond(pred: Expr, onT: Expr, onF: Expr) = for _ <- expect(pred, Type.Bool) x <- typeCheck(onT) _ <- expect(onF, x) yield x
pred : Type.Bool onT : X onF : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Cond pred onT onF : X
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Let name value body : ???
let x = 1 in x + 2
value : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Let name value body : ???
let x = 1 in x + 2
value : X body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Let name value body : ???
let x = 1 in x + 2
Γ |- value : X Γ |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Let name value body : ???
let x = 1 in x + 2
Γ |- value : X Γ |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Let name value body : ???
let x = 1 in x + 2
Γ |- value : X Γ |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Let name value body : ???
let x = 1 in x + 2
Γ |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Let name value body : ???
let x = 1 in x + 2
Γ |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Let name value body : ???
let x = 1 in x + 2
Γ |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Let name value body : Y
let x = 1 in x + 2
Γ |- Ref name : ???
let x = 1 in x + 2
Γ |- Ref name : ???
let x = 1 in x + 2
Γ |- Ref name : Γ(name)
let x = 1 in x + 2
Γ |- Ref name : Γ(name)
let x = 1 in x + 2
case class TypeEnv():
case class TypeEnv(env: List[TypeEnv.Binding]):
case class TypeEnv(env: List[TypeEnv.Binding]):object TypeEnv: case class Binding()
case class TypeEnv(env: List[TypeEnv.Binding]):object TypeEnv: case class Binding(name: String)
case class TypeEnv(env: List[TypeEnv.Binding]):object TypeEnv: case class Binding(name: String, tpe: Type)
case class TypeEnv(env: List[TypeEnv.Binding]): def lookup(name: String) =object TypeEnv: case class Binding(name: String, tpe: Type)
case class TypeEnv(env: List[TypeEnv.Binding]): def lookup(name: String) = env.find(_.name == name)object TypeEnv: case class Binding(name: String, tpe: Type)
case class TypeEnv(env: List[TypeEnv.Binding]): def lookup(name: String) = env.find(_.name == name) .map(_.tpe)object TypeEnv: case class Binding(name: String, tpe: Type)
case class TypeEnv(env: List[TypeEnv.Binding]): def lookup(name: String) = env.find(_.name == name) .map(_.tpe) .toRight(s"Type binding $name not found")object TypeEnv: case class Binding(name: String, tpe: Type)
case class TypeEnv(env: List[TypeEnv.Binding]): def lookup(name: String) = env.find(_.name == name) .map(_.tpe) .toRight(s"Type binding $name not found") def bind(name: String, tpe: Type) =object TypeEnv: case class Binding(name: String, tpe: Type)
case class TypeEnv(env: List[TypeEnv.Binding]): def lookup(name: String) = env.find(_.name == name) .map(_.tpe) .toRight(s"Type binding $name not found") def bind(name: String, tpe: Type) = TypeEnv.Binding(name, tpe)object TypeEnv: case class Binding(name: String, tpe: Type)
case class TypeEnv(env: List[TypeEnv.Binding]): def lookup(name: String) = env.find(_.name == name) .map(_.tpe) .toRight(s"Type binding $name not found") def bind(name: String, tpe: Type) = TypeEnv.Binding(name, tpe) :: envobject TypeEnv: case class Binding(name: String, tpe: Type)
case class TypeEnv(env: List[TypeEnv.Binding]): def lookup(name: String) = env.find(_.name == name) .map(_.tpe) .toRight(s"Type binding $name not found") def bind(name: String, tpe: Type) = TypeEnv(TypeEnv.Binding(name, tpe) :: env)object TypeEnv: case class Binding(name: String, tpe: Type)
case class TypeEnv(env: List[TypeEnv.Binding]): def lookup(name: String) = env.find(_.name == name) .map(_.tpe) .toRight(s"Type binding $name not found") def bind(name: String, tpe: Type) = TypeEnv(TypeEnv.Binding(name, tpe) :: env)object TypeEnv: case class Binding(name: String, tpe: Type) val empty = TypeEnv(List.empty)
def typeCheck(expr: Expr): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs) case Gt(lhs, rhs) => checkGt(lhs, rhs) case Cond(pred, onT, onF) => checkCond(pred, onT, onF)
def typeCheck(expr: Expr, Γ: TypeEnv): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs, Γ) case Gt(lhs, rhs) => checkGt(lhs, rhs, Γ) case Cond(pred, onT, onF) => checkCond(pred, onT, onF, Γ)
def typeCheck(expr: Expr, Γ: TypeEnv): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs, Γ) case Gt(lhs, rhs) => checkGt(lhs, rhs, Γ) case Cond(pred, onT, onF) => checkCond(pred, onT, onF, Γ) case Let(name, value, body) =>
Γ |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Let name value body : Y
def typeCheck(expr: Expr, Γ: TypeEnv): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs, Γ) case Gt(lhs, rhs) => checkGt(lhs, rhs, Γ) case Cond(pred, onT, onF) => checkCond(pred, onT, onF, Γ) case Let(name, value, body) => checkLet(name, value, body, Γ)
Γ |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Let name value body : Y
def checkLet(name: String, value: Expr, body: Expr, Γ: TypeEnv) =
Γ |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Let name value body : Y
def checkLet(name: String, value: Expr, body: Expr, Γ: TypeEnv) = for x <- typeCheck(value, Γ)
Γ |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Let name value body : Y
def checkLet(name: String, value: Expr, body: Expr, Γ: TypeEnv) = for x <- typeCheck(value, Γ) y <- typeCheck(body, ???)
Γ |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Let name value body : Y
def checkLet(name: String, value: Expr, body: Expr, Γ: TypeEnv) = for x <- typeCheck(value, Γ) y <- typeCheck(body, ???)
Γ |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Let name value body : Y
def checkLet(name: String, value: Expr, body: Expr, Γ: TypeEnv) = for x <- typeCheck(value, Γ) y <- typeCheck(body, Γ.bind(name, x))
Γ |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Let name value body : Y
def checkLet(name: String, value: Expr, body: Expr, Γ: TypeEnv) = for x <- typeCheck(value, Γ) y <- typeCheck(body, Γ.bind(name, x)) yield y
Γ |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Let name value body : Y
def typeCheck(expr: Expr, Γ: TypeEnv): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs, Γ) case Gt(lhs, rhs) => checkGt(lhs, rhs, Γ) case Cond(pred, onT, onF) => checkCond(pred, onT, onF, Γ) case Let(name, value, body) => checkLet(name, value, body, Γ)
Γ |- Ref name : Γ(name)
def typeCheck(expr: Expr, Γ: TypeEnv): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs, Γ) case Gt(lhs, rhs) => checkGt(lhs, rhs, Γ) case Cond(pred, onT, onF) => checkCond(pred, onT, onF, Γ) case Let(name, value, body) => checkLet(name, value, body, Γ) case Ref(name) =>
Γ |- Ref name : Γ(name)
def typeCheck(expr: Expr, Γ: TypeEnv): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs, Γ) case Gt(lhs, rhs) => checkGt(lhs, rhs, Γ) case Cond(pred, onT, onF) => checkCond(pred, onT, onF, Γ) case Let(name, value, body) => checkLet(name, value, body, Γ) case Ref(name) => Γ.lookup(name)
Γ |- Ref name : Γ(name)
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun param body : ???
let f = x -> x + 1 in f 2
Γ |- body : ???⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun param body : ???
let f = x -> x + 1 in f 2
Γ |- body : ???⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun param body : ???
let f = x -> x + 1 in f 2
Γ[param <- X] |- body : ???⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun param body : ???
let f = x -> x + 1 in f 2
Γ[param <- X] |- body : ???⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun param body : ???
let f = x -> x + 1 in f 2
Γ[param <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun param body : ???
let f = x -> x + 1 in f 2
Γ[param <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun param body : ???
let f = x -> x + 1 in f 2
Γ[param <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun param body : X -> Y
let f = x -> x + 1 in f 2
Γ[param <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun param body : X -> Y
let f = x -> x + 1 in f 2
Γ[param <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun param body : X -> Y
let f = x -> x + 1 in f 2
Γ[param <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun (param : X) body : X -> Y
let f = (x: Num) -> x + 1 in f 2
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Apply fun arg : ???
let f = (x: Num) -> x + 1 in f 2
Γ |- fun : ???⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Apply fun arg : ???
let f = (x: Num) -> x + 1 in f 2
Γ |- fun : ???⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Apply fun arg : ???
let f = (x: Num) -> x + 1 in f 2
Γ |- fun : X -> Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Apply fun arg : ???
let f = (x: Num) -> x + 1 in f 2
Γ |- fun : X -> Y Γ |- arg : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Apply fun arg : ???
let f = (x: Num) -> x + 1 in f 2
Γ |- fun : X -> Y Γ |- arg : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Apply fun arg : ???
let f = (x: Num) -> x + 1 in f 2
Γ |- fun : X -> Y Γ |- arg : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Apply fun arg : Y
let f = (x: Num) -> x + 1 in f 2
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Gt(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case LetRec(name: String, value: Expr, body: Expr) case Ref(name: String ) case Fun(param: String, body: Expr) case Apply(fun: Expr, arg: Expr)
Γ[param <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun (param : X) body : X -> Y
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Gt(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case LetRec(name: String, value: Expr, body: Expr) case Ref(name: String ) case Fun(param: String, pType: Type, body: Expr) case Apply(fun: Expr, arg: Expr)
Γ[param <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun (param : X) body : X -> Y
enum Type: case Num case Bool
Γ[param <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun (param : X) body : X -> Y
enum Type: case Num case Bool case Fun()
Γ[param <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun (param : X) body : X -> Y
enum Type: case Num case Bool case Fun(from: Type)
Γ[param <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun (param : X) body : X -> Y
enum Type: case Num case Bool case Fun(from: Type, to: Type)
Γ[param <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun (param : X) body : X -> Y
def typeCheck(expr: Expr, Γ: TypeEnv): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs, Γ) case Gt(lhs, rhs) => checkGt(lhs, rhs, Γ) case Cond(pred, onT, onF) => checkCond(pred, onT, onF, Γ) case Let(name, value, body) => checkLet(name, value, body, Γ) case Ref(name) => Γ.lookup(name)
Γ[param <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun (param : X) body : X -> Y
def typeCheck(expr: Expr, Γ: TypeEnv): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs, Γ) case Gt(lhs, rhs) => checkGt(lhs, rhs, Γ) case Cond(pred, onT, onF) => checkCond(pred, onT, onF, Γ) case Let(name, value, body) => checkLet(name, value, body, Γ) case Ref(name) => Γ.lookup(name) case Fun(param, x, body) =>
Γ[param <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun (param : X) body : X -> Y
def typeCheck(expr: Expr, Γ: TypeEnv): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs, Γ) case Gt(lhs, rhs) => checkGt(lhs, rhs, Γ) case Cond(pred, onT, onF) => checkCond(pred, onT, onF, Γ) case Let(name, value, body) => checkLet(name, value, body, Γ) case Ref(name) => Γ.lookup(name) case Fun(param, x, body) => checkFun(param, x, body Γ)
Γ[param <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun (param : X) body : X -> Y
def checkFun(param: String, x: Type, body: Expr, Γ: TypeEnv) =
Γ[param <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun (param : X) body : X -> Y
def checkFun(param: String, x: Type, body: Expr, Γ: TypeEnv) = for y <- typeCheck(body, ???)
Γ[param <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun (param : X) body : X -> Y
def checkFun(param: String, x: Type, body: Expr, Γ: TypeEnv) = for y <- typeCheck(body, ???)
Γ[param <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun (param : X) body : X -> Y
def checkFun(param: String, x: Type, body: Expr, Γ: TypeEnv) = for y <- typeCheck(body, Γ.bind(param, x))
Γ[param <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun (param : X) body : X -> Y
def checkFun(param: String, x: Type, body: Expr, Γ: TypeEnv) = for y <- typeCheck(body, Γ.bind(param, x)) yield x -> y
Γ[param <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯Γ |- Fun (param : X) body : X -> Y
def typeCheck(expr: Expr, Γ: TypeEnv): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs, Γ) case Gt(lhs, rhs) => checkGt(lhs, rhs, Γ) case Cond(pred, onT, onF) => checkCond(pred, onT, onF, Γ) case Let(name, value, body) => checkLet(name, value, body, Γ) case Ref(name) => Γ.lookup(name) case Fun(param, pType, body) => checkFun(param, pType, body, Γ)
Γ |- fun : X -> Y Γ |- arg : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Apply fun arg : Y
def typeCheck(expr: Expr, Γ: TypeEnv): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs, Γ) case Gt(lhs, rhs) => checkGt(lhs, rhs, Γ) case Cond(pred, onT, onF) => checkCond(pred, onT, onF, Γ) case Let(name, value, body) => checkLet(name, value, body, Γ) case Ref(name) => Γ.lookup(name) case Fun(param, pType, body) => checkFun(param, pType, body, Γ) case Apply(fun, arg) =>
Γ |- fun : X -> Y Γ |- arg : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Apply fun arg : Y
def typeCheck(expr: Expr, Γ: TypeEnv): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs, Γ) case Gt(lhs, rhs) => checkGt(lhs, rhs, Γ) case Cond(pred, onT, onF) => checkCond(pred, onT, onF, Γ) case Let(name, value, body) => checkLet(name, value, body, Γ) case Ref(name) => Γ.lookup(name) case Fun(param, pType, body) => checkFun(param, pType, body, Γ) case Apply(fun, arg) => checkApply(fun, arg, Γ)
Γ |- fun : X -> Y Γ |- arg : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Apply fun arg : Y
def checkApply(fun: Expr, arg: Expr, Γ: TypeEnv) =
Γ |- fun : X -> Y Γ |- arg : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Apply fun arg : Y
def checkApply(fun: Expr, arg: Expr, Γ: TypeEnv) = typeCheck(fun, Γ).flatMap:
Γ |- fun : X -> Y Γ |- arg : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Apply fun arg : Y
def checkApply(fun: Expr, arg: Expr, Γ: TypeEnv) = typeCheck(fun, Γ).flatMap: case x -> y =>
Γ |- fun : X -> Y Γ |- arg : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Apply fun arg : Y
def checkApply(fun: Expr, arg: Expr, Γ: TypeEnv) = typeCheck(fun, Γ).flatMap: case x -> y => expect(arg, x, Γ)
Γ |- fun : X -> Y Γ |- arg : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Apply fun arg : Y
def checkApply(fun: Expr, arg: Expr, Γ: TypeEnv) = typeCheck(fun, Γ).flatMap: case x -> y => expect(arg, x, Γ) .map(_ => y)
Γ |- fun : X -> Y Γ |- arg : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Apply fun arg : Y
def checkApply(fun: Expr, arg: Expr, Γ: TypeEnv) = typeCheck(fun, Γ).flatMap: case x -> y => expect(arg, x, Γ) .map(_ => y) case other =>
Γ |- fun : X -> Y Γ |- arg : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Apply fun arg : Y
def checkApply(fun: Expr, arg: Expr, Γ: TypeEnv) = typeCheck(fun, Γ).flatMap: case x -> y => expect(arg, x, Γ) .map(_ => y) case other => Left(s"Expected function, found $other")
Γ |- fun : X -> Y Γ |- arg : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- Apply fun arg : Y
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name value body : ???
let rec sum = (lower: Num) -> (upper: Num) -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
??? |- value : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name value body : ???
let rec sum = (lower: Num) -> (upper: Num) -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
??? |- value : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name value body : ???
let rec sum = (lower: Num) -> (upper: Num) -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
Γ[name <- X] |- value : X⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name value body : ???
let rec sum = (lower: Num) -> (upper: Num) -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
Γ[name <- X] |- value : X ??? |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name value body : ???
let rec sum = (lower: Num) -> (upper: Num) -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
Γ[name <- X] |- value : X ??? |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name value body : ???
let rec sum = (lower: Num) -> (upper: Num) -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
Γ[name <- X] |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name value body : ???
let rec sum = (lower: Num) -> (upper: Num) -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
Γ[name <- X] |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name value body : ???
let rec sum = (lower: Num) -> (upper: Num) -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
Γ[name <- X] |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name value body : Y
let rec sum = (lower: Num) -> (upper: Num) -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
Γ[name <- X] |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name value body : Y
let rec sum = (lower: Num) -> (upper: Num) -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
Γ[name <- X] |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name value body : Y
let rec sum = (lower: Num) -> (upper: Num) -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
Γ[name <- X] |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name (value : X) body : Y
let rec (sum: Num -> Num -> Num) = (lower: Num) -> (upper: Num) -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Gt(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case LetRec(name: String, value: Expr, body: Expr) case Ref(name: String) case Fun(param: String, paramType: Type, body: Expr) case Apply(fun: Expr, arg: Expr)
Γ[name <- X] |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name (value : X) body : Y
enum Expr: case Num(value: Int) case Bool(value: Boolean) case Add(lhs: Expr, rhs: Expr) case Gt(lhs: Expr, rhs: Expr) case Cond(pred: Expr, onT: Expr, onF: Expr) case Let(name: String, value: Expr, body: Expr) case LetRec(name: String, value: Expr, vType: Type, body: Expr) case Ref(name: String) case Fun(param: String, paramType: Type, body: Expr) case Apply(fun: Expr, arg: Expr)
Γ[name <- X] |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name (value : X) body : Y
def typeCheck(expr: Expr, Γ: TypeEnv): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs, Γ) case Gt(lhs, rhs) => checkGt(lhs, rhs, Γ) case Cond(pred, onT, onF) => checkCond(pred, onT, onF, Γ) case Let(name, value, body) => checkLet(name, value, body, Γ) case Ref(name) => Γ.lookup(name) case Apply(fun, arg) => checkApply(fun, arg, Γ) case Fun(param, pType, body) => checkFun(param, pType, body, Γ)
Γ[name <- X] |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name (value : X) body : Y
def typeCheck(expr: Expr, Γ: TypeEnv): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs, Γ) case Gt(lhs, rhs) => checkGt(lhs, rhs, Γ) case Cond(pred, onT, onF) => checkCond(pred, onT, onF, Γ) case Let(name, value, body) => checkLet(name, value, body, Γ) case Ref(name) => Γ.lookup(name) case Apply(fun, arg) => checkApply(fun, arg, Γ) case Fun(param, pType, body) => checkFun(param, pType, body, Γ) case LetRec(name, value, x, body) =>
Γ[name <- X] |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name (value : X) body : Y
def typeCheck(expr: Expr, Γ: TypeEnv): Either[String, Type] = expr match case Num(value) => Right(Type.Num) case Bool(value) => Right(Type.Bool) case Add(lhs, rhs) => checkAdd(lhs, rhs, Γ) case Gt(lhs, rhs) => checkGt(lhs, rhs, Γ) case Cond(pred, onT, onF) => checkCond(pred, onT, onF, Γ) case Let(name, value, body) => checkLet(name, value, body, Γ) case Ref(name) => Γ.lookup(name) case Apply(fun, arg) => checkApply(fun, arg, Γ) case Fun(param, pType, body) => checkFun(param, pType, body, Γ) case LetRec(name, value, x, body) => checkLetRec(name, value, x, body, Γ)
Γ[name <- X] |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name (value : X) body : Y
def checkLetRec(name: String, value: Expr, x: Type, body: Expr, Γ: TypeEnv) =
Γ[name <- X] |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name (value : X) body : Y
def checkLetRec(name: String, value: Expr, x: Type, body: Expr, Γ: TypeEnv) = val eʹ = Γ.bind(name, x)
Γ[name <- X] |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name (value : X) body : Y
def checkLetRec(name: String, value: Expr, x: Type, body: Expr, Γ: TypeEnv) = val eʹ = Γ.bind(name, x) for _ <- expect(value, x, eʹ)
Γ[name <- X] |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name (value : X) body : Y
def checkLetRec(name: String, value: Expr, x: Type, body: Expr, Γ: TypeEnv) = val eʹ = Γ.bind(name, x) for _ <- expect(value, x, eʹ) y <- typeCheck(body, eʹ)
Γ[name <- X] |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name (value : X) body : Y
def checkLetRec(name: String, value: Expr, x: Type, body: Expr, Γ: TypeEnv) = val eʹ = Γ.bind(name, x) for _ <- expect(value, x, eʹ) y <- typeCheck(body, eʹ) yield y
Γ[name <- X] |- value : X Γ[name <- X] |- body : Y⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Γ |- LetRec name (value : X) body : Y
1 + true
val expr = Add( Num(1), Bool(true))
typeCheck(expr, TypeEnv.empty)
1 + true
val expr = Add( Num(1), Bool(true))
typeCheck(expr, TypeEnv.empty)// val res9: Either[String, Type] = Left(Expected Num, found Bool)
let rec (sum: Num -> Num -> Num) = (lower: Num) -> (upper: Num) -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
val expr = LetRec( // ...)
typeCheck(expr, TypeEnv.empty)
let rec (sum: Num -> Num -> Num) = (lower: Num) -> (upper: Num) -> if lower > upper then 0 else lower + (sum (lower + 1) upper) in sum 1 10
val expr = LetRec( // ...)
typeCheck(expr, TypeEnv.empty)// val res10: Either[String, Type] = Right(Num)
Type checking is very similar to interpretation
It follows the same "formalise / implement" logic
Type checking is very similar to interpretation
It follows the same "formalise / implement" logic
We're still allowing illegal programs though...
Programs are represented as ASTs
We use formal semantics to reason about them
Programs are represented as ASTs
We use formal semantics to reason about them
Implementation is then relatively straightforward
enum TypedExpr[A]: case Num(value: Int) extends TypedExpr[Type.Num.type] case Bool(value: Boolean) extends TypedExpr[Type.Bool.type] case Add(lhs: TypedExpr[Type.Num.type], rhs: TypedExpr[Type.Num.type]) extends TypedExpr[Type.Num.type] case Gt(lhs: TypedExpr[Type.Num.type], rhs: TypedExpr[Type.Num.type]) extends TypedExpr[Type.Bool.type] case Cond[A](pred: TypedExpr[Type.Bool.type], onT: TypedExpr[A], onF: TypedExpr[A]) extends TypedExpr[A] case Let[A, B](name: String, value: TypedExpr[A], body: TypedExpr[B]) extends TypedExpr[B] case LetRec[A](name: String, value: TypedExpr[Type.Fun], body: TypedExpr[A]) extends TypedExpr[A] case Ref[A](name: String) extends TypedExpr[A] case Fun[A](param: String, body: TypedExpr[A]) extends TypedExpr[Type.Fun] case Apply[A, B](fun: TypedExpr[Type.Fun], arg: TypedExpr[A]) extends TypedExpr[B]
enum Type: case Num case Bool case Fun(from: Type, to: Type)object Type: type Num = Type.Num.type type Bool = Type.Bool.type
enum TypedExpr[A]: case Num(value: Int) extends TypedExpr[Type.Num] case Bool(value: Boolean) extends TypedExpr[Type.Bool] case Add(lhs: TypedExpr[Type.Num], rhs: TypedExpr[Type.Num]) extends TypedExpr[Type.Num] case Gt(lhs: TypedExpr[Type.Num], rhs: TypedExpr[Type.Num]) extends TypedExpr[Type.Bool] case Cond[A](pred: TypedExpr[Type.Bool], onT: TypedExpr[A], onF: TypedExpr[A]) extends TypedExpr[A] case Let[A, B](name: String, value: TypedExpr[A], body: TypedExpr[B]) extends TypedExpr[B] case LetRec[A](name: String, value: TypedExpr[Type.Fun], body: TypedExpr[A]) extends TypedExpr[A] case Fun[A](param: String, body: TypedExpr[A]) extends TypedExpr[Type.Fun] case Ref[A](name: String) extends TypedExpr[A] case Apply[A, B](fun: TypedExpr[Type.Fun], arg: TypedExpr[A]) extends TypedExpr[B]
enum Type: case Num case Bool case Fun[From <: Type, To <: Type](from: From, to: To)object Type: type Num = Type.Num.type type Bool = Type.Bool.typetype ->[A <: Type, B <: Type] = Type.Fun[A, B]
enum TypedExpr[A <: Type]: case Num(value: Int) extends TypedExpr[Type.Num] case Bool(value: Boolean) extends TypedExpr[Type.Bool] case Add(lhs: TypedExpr[Type.Num], rhs: TypedExpr[Type.Num]) extends TypedExpr[Type.Num] case Gt(lhs: TypedExpr[Type.Num], rhs: TypedExpr[Type.Num]) extends TypedExpr[Type.Bool] case Cond[A <: Type](pred: TypedExpr[Type.Bool], onT: TypedExpr[A], onF: TypedExpr[A]) extends TypedExpr[A] case Let[A <: Type, B <: Type](name: String, value: TypedExpr[A], body: TypedExpr[B]) extends TypedExpr[B] case LetRec[A <: Type, B <: Type, C <: Type](name: String, value: TypedExpr[A -> B], body: TypedExpr[C]) extends TypedExpr[C] case Ref[A <: Type](name: String) extends TypedExpr[A] case Fun[A <: Type, B <: Type](param: String, body: TypedExpr[B]) extends TypedExpr[A -> B] case Apply[A <: Type, B <: Type](fun: TypedExpr[A -> B], arg: TypedExpr[A]) extends TypedExpr[B]
import TypedExpr.*Let( name = "x", value = Bool(true), body = Add(Ref("x"), Num(1)))// val res11: TypedExpr[Type.Num.type] = Let(x,Bool(true),Add(Ref(x),Num(1)))
val expr: TypedExpr[Type.Bool -> Type.Num] = Fun( param = "x", body = Add(Ref("x"), Num(1)))
Keyboard shortcuts
↑, ←, Pg Up, k | Go to previous slide |
↓, →, Pg Dn, Space, j | Go to next slide |
Home | Go to first slide |
End | Go to last slide |
Number + Return | Go to specific slide |
b / m / f | Toggle blackout / mirrored / fullscreen mode |
c | Clone slideshow |
p | Toggle presenter mode |
t | Restart the presentation timer |
?, h | Toggle this help |
Esc | Back to slideshow |