Final Exam
CS 320, Fall 2018
Student id: Name:
Instructions: You have 180 minutes to complete this closed-book, closed-note, closed-computer exam. Please
write all answers in the provided space. Korean students should write your answers in Korean.
The solutions in this file may omit necessary details. You are not
supposed to ask TAs to SOLVE the problems from scratch. When
you have specific questions while solving the problems, you are
more than welcome to ask them to TAs.
1) (5pts) Summarize what you learned from this course in one sentence.
2) (5pts) Write what you learned from the “Growing a Language” video lecture in one sentence.
3) (5pts) Suppose a garbage-collected interepreter uses the following five kinds of records:
– Tag 1: a record containing two pointers
– Tag 2: a record containing one pointer and one integer
– Tag 3: a record containing one integer
– Tag 4: a record containing one integer and one pointer
– Tag 99: forwarding pointer (to to-space)
The interpreter has one register, which always contains a pointer, and a memory pool of size 26. The
allocator/collector is a two-space copying collector, so each space is of size 13. Records are allocated
consecutively in to-space, starting from the first memory location, 0.
The following is a snapshot of memory just before a collection where all memory has been allocated:
– Register: 8
– From space: 1 3 8 3 0 4 7 3 2 0 8 3 42
What are the values in the register, the from-space, and the to-space after collection? Assume that
unallocated memory in to-space contains 0.
– Register: (1pt) 0
– From space: (2pts) 99 3 8 99 6 4 7 3 99 0 8 3 42
– To space: (2pts) 2 3 8 1 6 0 3 0 0 0 0 0 0
OR
– Register: (1pt) 13
– From space: (2pts) 99 16 8 99 19 4 7 3 99 13 8 3 42
– To space: (2pts) 2 16 8 1 19 13 3 0 0 0 0 0 0
1
4) (5pts) Compare programming languages with and without garbage collection. What are such pro-
gramming languages? What are pros and cons?
GC: Java, Scala, · · · / safe memory management / slow
no GC: C, C++, · · · / fast / memory-related errors
5) (5pts) Which of the following produce different results in an eager language and a lazy language?
Both produce the same result if they both produce the same number, they both produce a procedure
(even if the procedure doesn’t behave exactly the same when applied), or they both produce an error.
Show the results of each expression in an eager language and a lazy language.
a) {{fun {y} 12} {1 2}}
eager: error lazy: 12
b) {fun {x} {{fun {y} 12} {1 2}}}
eager: closure lazy: closure
c) {+ 1 {fun {y} 12}}
eager: error lazy: error
d) {+ 1 {{fun {x} {+ 1 13}} {+ 1 {fun {z} 12}}}}
eager: error lazy: 15
e) {+ 1 {{fun {x} {+ x 13}} {+ 1 {fun {z} 12}}}}
eager: error lazy: error
2
6) (5pts) Consider the following LFAE expression:
n ∈ Num
fin
e ::= n σ ∈ Env = Var −→ Val
| e+e x ∈ Var
| x hλx.e, σi ∈ Clo = Var × Expr × Env
| λx. e v ∈ Val = Z + Clo + ExprV
| ee (e, σ) ∈ ExprV = Expr × Env
with the following “strict” evaluation of the form v ⇓ v :
σ ` e ⇒ v1 v1 ⇓ v2
n⇓n hλx.e, σi ⇓ hλx.e, σi
(e, σ) ⇓ v2
Write the operational semantics of LFAE, where a value is strictly evaluted when it is used, that is,
strict evaluation is deferred as much as possible. Thus, the evaluation of “λx.x y” is not an error.
– n
σ`n⇒n
– e+e
σ ` e1 ⇒ v1 v1 ⇓ n1 σ ` e2 ⇒ v2 v2 ⇓ n2
σ ` e1 + e2 ⇒ n1 + n2
– x
x ∈ Dom(σ)
σ ` x ⇒ σ(x)
– λx. e
σ ` λx. e ⇒ hλx.e, σi
– ee
σ ` e1 ⇒ v1 v1 ⇓ hλx.e, σ 0 i σ 0 [x 7→ (e2 , σ)] ` e ⇒ v2
σ ` e1 e2 ⇒ v2
3
7) (5pts) Write the typing rule for the following expression:
{with {x τ e1 } e2 }
Γ ` τ Γ ` e1 : τ Γ[x : τ ] ` e2 : τ 0
Γ ` {with {x τ e1 } e2 } : τ 0
8) (5pts) Consider the following partial implementation of the compile function:
type CEnv = List[String]
def compile(fae: FAE, cenv: CEnv): CFAE = fae match {
case Num(n) => CNum(n)
case Add(l, r) => CAdd(compile(l, cenv), compile(r, cenv))
case Sub(l, r) => CSub(compile(l, cenv), compile(r, cenv))
case Id(name) => CId(locate(name, cenv))
case Fun(param, body) => CFun(compile(body, param :: cenv))
case App(l, r) => CApp(compile(l, cenv), compile(r, cenv))
}
def locate(name: String, cenv: CEnv): Int = cenv match {
case Nil => error("a free identifier: $name")
case h::t => if (name == h) 0 else locate(name, t) + 1
}
What is the result of calling the compile function with the following expression:
{{{{fun {x} {fun {y} {fun {z} {+ x {+ y z}}}}} 8} 42} 320}
CApp(CApp(CApp(CFun(CFun(CFun(CAdd(CId(2), CAdd(CId(1), CId(0)))))),
CNum(8)),
CNum(42)),
CNum(320))
4
9) (10pts) Consider the following grammar:
e ::= n number
| x identifier
| e+e addition of two numbers
| ref e location construction with a given initial value
| !e dereferencing
| e := e assignment evaluating the right-hand side (RHS) first, producing the value of RHS
| e;e sequencing
| let x = e in e name binding
v ::= n number
| l location
τ ::= num type of numbers
| ref τ type of locations that contain values of type τ
x∈ Id
l∈ Loc
v∈ Val
σ∈ Id → Loc
M∈ Loc → Val
where evaluation of “let x = 42 in x” results in 42.
a) (5pts) Write the operational semantics of the form σ, M ` e ⇒ v, M for the expressions with
the BFAE semantics.
σ, M ` n ⇒ n, M
σ, M ` x ⇒ M (σ(x)), M
σ, M ` e1 ⇒ n1 , M1 σ, M1 ` e2 ⇒ n2 , M2
σ, M ` e1 + e2 ⇒ n1 + n2 , M2
σ, M ` e ⇒ v, M 0 l 6∈ Dom(M 0 )
σ, M ` ref e ⇒ l, M 0 [l 7→ v]
σ, M ` e ⇒ l, M 0
σ, M ` ! e ⇒ M 0 (l), M 0
σ, M ` e2 ⇒ v, M1 σ, M1 ` e1 ⇒ l, M2
σ, M ` e1 := e2 ⇒ v, M2 [l 7→ v]
σ, M ` e1 ⇒ v1 , M1 σ, M1 ` e2 ⇒ v2 , M2
σ, M ` e1 ; e2 ⇒ v2 , M2
σ, M ` e1 ⇒ v1 , M1 σ[x 7→ l], M1 [l 7→ v1 ] ` e2 ⇒ v2 , M2 l 6∈ Dom(M1 )
σ, M ` let x = e1 in e2 ⇒ v2 , M2
5
b) (5pts) Write the typing rules of the form Γ ` e : τ for the expressions. Assignments should not
change the types of the values at a given location.
Γ ` n : num
x ∈ Dom(Γ)
Γ ` x : Γ(x)
Γ ` e1 : num Γ1 ` e2 : num
Γ ` e1 + e2 : num
Γ`e:τ
Γ ` ref e : ref τ
Γ ` e : ref τ
Γ ` !e : τ
Γ ` e2 : τ Γ ` e1 : ref τ
Γ ` e1 := e2 : τ
Γ ` e1 : τ1 Γ ` e2 : τ2
Γ ` e1 ; e2 : τ2
Γ ` e1 : τ1 Γ[x : τ1 ] ` e2 : τ2
Γ ` let x = e1 in e2 : τ2
6
10) (10pts) Consider the following KCFAE expression:
e ::= n κ ::= [] (mkK) e∈ Expr
fin
| e+e | [ + (e, σ)] :: κ (addSecondK e ds k) σ∈ Env =Var −→ Val
| x | [v + ] :: κ (doAddK v k) x∈ Var
| λx. e | [ (e, σ)] :: κ (appArgK e ds k) hλx.e, σi ∈ Clo =Var × Expr × Env
| ee | [v ] :: κ (doAppK v k) v∈ Val =Z + Clo + Cont
| withcc x e κ∈ Cont
Write the big-step operational semantics of KCFAE of the form σ, κ ` e ⇒ v using the continue se-
mantics of the form v1 7→ κ ⇓ v2 , which denotes that v2 is the result of continuation κ taking the
value v1 .
a) v 7→ κ ⇓ v
∗ []
v 7→ [] ⇓ v
∗ [ + (e, σ)] :: κ
σ, [v1 + ] :: κ ` e ⇒ v
v1 7→ [ + (e, σ)] :: κ ⇓ v
∗ [v + ] :: κ (1pt)
n1 + n2 7→ κ ⇓ v
n2 7→ [n1 + ] :: κ ⇓ v
∗ [ (e, σ)] :: κ (1pt)
σ, [v ] :: κ ` e ⇒ v 0
v 7→ [ (e, σ)] :: κ ⇓ v 0
∗ [v ] :: κ (1pt + 2pts)
σ[x 7→ v2 ], κ ` e ⇒ v
v2 7→ [hλx.e, σi ] :: κ ⇓ v
v2 7→ κ0 ⇓ v
v2 7→ [κ0 ] :: κ ⇓ v
7
b) σ, κ ` e ⇒ v
∗ n
n 7→ κ ⇓ v
σ, κ ` n ⇒ v
∗ e+e
σ, [ + (e2 , σ)] :: κ ` e1 ⇒ v
σ, κ ` e1 + e2 ⇒ v
∗ x
x ∈ Dom(σ) σ(x) 7→ κ ⇓ v
σ, κ ` x ⇒ v
∗ λx. e
hλx.e, σi 7→ κ ⇓ v
σ, κ ` λx. e ⇒ v
∗ ee
σ, [ (e2 , σ)] :: κ ` e1 ⇒ v
σ, κ ` e1 e2 ⇒ v
∗ withcc x e
σ[x 7→ κ], κ ` e ⇒ v
σ, κ ` withcc x e ⇒ v
8
11) (10pts) Consider the following KCFAE expression:
e ::= n κ ::= n∈ Z v ∈Val = Z + Clo + Continuation
| e+e | σ ` e :: κ interpretation x∈ Var hλx.e, σi ∈Clo = Var × Expr × Env
fin
| x | (+) :: κ addition e∈ Expr σ ∈Env = Var −→ Val
| λx. e | (@) :: κ application κ∈ Cont hκ, si ∈Continuation = Cont × Stack
| ee s ::= s∈ Stack
| withcc x e | v :: s
a) Fill in the missing five cases of the small-step operational semantics of KCFAE of the form κ || s → κ || s .
σ ` n :: κ || s → κ || n :: s
σ ` e1 + e2 :: κ || s → σ ` e1 :: σ ` e2 :: (+) :: κ || s
(+) :: κ || n2 :: n1 :: s → κ || n1 + n2 :: s
σ ` x :: κ || s → κ || σ(x) :: s
σ ` λx. e :: κ || s → κ || hλx. e, σi :: s
σ ` e1 e2 :: κ || s → σ ` e1 :: σ ` e2 :: (@) :: κ || s
(@) :: κ || v :: hλx. e, σi :: s → σ[x 7→ v] ` e :: κ || s
(@) :: κ || v :: hκ0 , s0 i :: s → κ0 || v :: s0
σ ` withcc x e :: κ || s → σ[x 7→ hκ, si] ` e :: κ || s
9
b) Show the interpretation steps of the expression (withcc x (42 + (x 2))) + 8 where the value of a
parenthesized expression (e) is the value of e.
∅ ` (withcc x (42 + (x 2))) + 8 :: ||
≡ ∅ ` e1 + 8 :: ||
→ ∅ ` e1 :: ∅ ` 8 :: (+) :: ||
≡ ∅ ` withcc x e2 :: ∅ ` 8 :: (+) :: ||
→ σ1 ` e2 :: ∅ ` 8 :: (+) :: ||
≡ σ1 ` 42 + (x 2) :: ∅ ` 8 :: (+) :: ||
→ σ1 ` 42 :: σ1 ` (x 2) :: (+) :: ∅ ` 8 :: (+) :: ||
→ σ1 ` (x 2) :: (+) :: ∅ ` 8 :: (+) :: || 42 ::
→ σ1 ` x :: σ1 ` 2 :: (@) :: (+) :: ∅ ` 8 :: (+) :: || 42 ::
→ σ1 ` 2 :: (@) :: (+) :: ∅ ` 8 :: (+) :: || h∅ ` 8 :: (+) :: , i :: 42 ::
→ (@) :: (+) :: ∅ ` 8 :: (+) :: || 2 :: h∅ ` 8 :: (+) :: , i :: 42 ::
→ ∅ ` 8 :: (+) :: || 2 ::
→ (+) :: || 8 :: 2 ::
→ || 10 ::
e0 = e1 + 8
e1 = withcc x e2
where e2 = 42 + e3
e3 = (x 2)
σ1 = [x 7→ h∅ ` 8 :: (+) :: , i]
10
12) (5pts) Rewrite the following code using explicit annotation of polymorphic types with tyfun and @ to
replace all the occurrences of ? with types and to make function calls to take explicit type arguments.
Γ[α] ` e : τ Γ ` τ0 Γ ` e : (∀α τ1 )
Γ ` [tyfun [α] e] : (∀α τ ) Γ ` [@ e τ0 ] : τ1 [α ← τ0 ]
Γ[α] ` τ
[. . . α . . .] ` α
Γ ` (∀α τ )
{with {f : ? {fun {g : ?} {fun {v : ?} {g v}}}}
{with {g : ? {fun {x : ?} x}}
{{f g} 10}}}
{with {f : (∀α (∀β ((α → β) → (α → β))))
[tyfun [α] [tyfun [β]
{fun {g : (α → β)} {fun {v : α} {g v}}}]]}
{with {g : (∀α (α → α))
[tyfun [α] {fun {x : α} x}]}
{{[@ [@ f num] num] [@ g num]} 10}}}
f’s type 1pt, f’s body 1pt, g’s type 1pt, g’s body 1pt, app 1pt
11
13) (15pts) We’d like to allow the following expression:
{withtype {{alpha list} {empty num}
{cons (alpha * {alpha list})}}
{rec {len : (forall alpha ({alpha list} -> num))
[tyfun [alpha]
{fun {l : {alpha list}}
{cases {alpha list} l
{empty {n} 0}
{cons {fxr}
{+ 1 {len {snd fxr}}}}}}]}
{+ {[@ len num] {[@ cons num] {pair 1 {[@ empty num] 0}}}}
{[@ len (num -> num)] {[@ empty (num -> num)] 0}}}}}
and of course the following as well:
{withtype {fruit {banana num} {apple bool}}
{{fun {x : fruit} {cases fruit x {banana {n} {+ n 9}} {apple {b} 76}}}
{banana 2}}}
Thus, we define the following language:
e ::= n
| {+ e e}
| x
| {fun {x:τ } e}
| {e e}
| {rec {x:τ e} e}
| {pair e e}
| {fst e}
| {snd e}
| {withtype {γ {x τ } {x τ }} e}
| {cases γ e {x {x} e} {x {x} e}}
| [tyfun [α] e]
| [@ e τ ]
τ ::= num
| (τ → τ )
| (τ × τ )
| γ
| α
| (∀α τ )
γ ::= {α t}
| t
12
a) (4pts) Write the operational semantics of the form σ ` e ⇒ v for the expressions withtype,
cases, and {e e}.
(4pts) 1pt for each rule
σ[x1 7→ cV(1), x2 7→ cV(2)] ` e ⇒ v
σ ` {withtype {γ {x1 τ1 } {x2 τ2 }} e} ⇒ v
σ ` e1 ⇒ cV(i) σ ` e2 ⇒ v i = 1 or 2
σ ` {e1 e2 } ⇒ vV(i,v)
σ ` e1 ⇒ hλx.e, σ 0 i σ ` e2 ⇒ v σ 0 [x 7→ v] ` e ⇒ v 0
σ ` {e1 e2 } ⇒ v 0
σ ` e0 ⇒ vV(i,v) σ[yi 7→ v] ` ei ⇒ v 0 i = 1 or 2
σ ` {cases γ e0 {x1 {y1 } e1 } {x2 {y2 } e2 }} ⇒ v 0
b) (6pts) Write the typing rules of the form Γ ` e : τ for the expressions withtype and cases and
the well-formedness of user-defined types.
(6pts) 1 / 2 / 2 / 1
Γ0 = Γ[t = x1 @τ1 + x2 @τ2 , x1 : (τ1 → t), x2 : (τ2 → t)]
Γ0 ` τ1 Γ0 ` τ2 Γ0 ` e : τ0 t not in τ0
Γ ` {withtype {t {x1 τ1 } {x2 τ2 }} e} : τ0
Γ0 = Γ[{α t} = x1 @τ1 + x2 @τ2 , x1 : (∀α (τ1 → {α t})), x2 : (∀α (τ2 → {α t})), α]
Γ0 ` τ1 Γ0 ` τ2 Γ0 ` e : τ0 {α t} not in τ0
Γ ` {withtype {{α t} {x1 τ1 } {x2 τ2 }} e} : τ0
Γ = [. . . γ = x1 @τ1 + x2 @τ2 . . .]
Γ ` e0 : γ Γ[y1 : τ1 ] ` e1 : τ0 Γ[y2 : τ2 ] ` e2 : τ0
Γ ` {cases γ e0 {x1 {y1 } e1 } {x2 {y2 } e2 }} : τ0
[. . . {α t} = . . .] ` {α t}
[. . . t = . . .] ` t
13
c) (5pts) Consider the following expression:
{withtype {fruit {apple num} {banana num}}
{{withtype {color {apple num} {banana num}}
{fun {x : fruit}
{cases fruit x
{apple {a} {apple {+ a 1}}}
{banana {b} {banana {+ b 1}}}}}}
{apple 42}}}
If the result of type checking the expression is fruit, explain why in detail. Otherwise, revise the
typing rules to make it fruit.
Γ = [· · · t = x1 @τ1 + x2 @τ2 · · · ] Γ0 = Γ[x1 : (τ1 → t), x2 : (τ2 → t)]
Γ ` e0 : t Γ0 [y1 : τ1 ] ` e1 : τ Γ0 [y2 : τ2 ] ` e2 : τ
Γ ` {cases t e0 {x1 {y1 } e1 } {x2 {y2 } e2 }} : τ
14
14) (10pts) Consider the following language:
class declaration d ::= class C extends C { g ∗ k m∗ }
field declaration g ::= x:C;
constructor declaration k ::= C((x:C)∗ ) { super(x∗ ); (this.x = x;)∗ }
method declaration m ::= f ((x:C)∗ ):C { return e; }
expression e ::= x | e.x | e.f (e∗ ) | new C(e∗ )
where metavariables C, D, and E range over class names, x ranges over field names, and f ranges over
method names. We assume that the set of variables includes the special variable this, which cannot
be used as the name of an argument to a method. Instead, it is implicitly bound in every method
declaration. The evaluation rule for method invocation will substitute an appropriate object for this,
in addition to substituting the argument values for the parameters.
With the following subtyping rules:
C <: D D <: E class C extends D {· · · }
C <: C
C <: E C <: D
and the following helper functions:
fields(C) = x1 : C1 · · · xn : Cn the fields of class C are x1 to xn of types C1 to Cn , respectively
mtype(C, f ) = C1 · · · Cn → Cn+1 the type of method f defined in class C is C1 · · · Cn → Cn+1
ctype(C) = C1 · · · Cn → C the type of the constructor of class C is C1 · · · Cn → C
a) Write the typing rules of the form Γ ` e : C for the expressions. The typing rules for constructors
and method invocations check that each actual argument has a type that is a subtype of the
corresponding formal parameter type.
x ∈ Dom(Γ)
Γ ` x : Γ(x)
Γ`e:C fields(C) = x1 : C1 · · · xn : Cn
Γ ` e.xi : Ci
Γ`e:C mtype(C, f ) = C1 · · · Cn → Cn+1
Γ ` e1 : D1 ··· Γ ` en : Dn D1 <: C1 ··· Dn <: Cn
Γ ` e.f (e1 , · · · en ) : Cn+1
ctype(C) = C1 · · · Cn → C
Γ ` e1 : D1 ··· Γ ` en : Dn D1 <: C1 ··· Dn <: Cn
Γ ` new C(e1 , · · · en ) : C
15
b) The following judgment states that:
C ` f (x1 :C1 , · · · xn :Cn ):Cn+1 { return e; }
the method declaration defined in C is well typed. Write its typing rule which checks the following:
∗ The type of f ’s body expression e should be a subtype of the annotated return type Cn+1 .
∗ When class C explicitly extends D (class C extends D { · · · }), if D defines any method
of name f , the type of f in D should be the same with the type of f in C.
[x1 : C1 · · · xn : Cn this : C] ` e : C 0 C 0 <: Cn+1
class C extends D { · · · }
0
mtype(D, f ) = C10 · · · Cn0 0 → Cn0 0 +1 ⇒ n = n0 ∧ C1 = C10 ∧ · · · Cn+1 = Cn+1
C ` f (x1 :C1 , · · · xn :Cn ):Cn+1 { return e; }
16