0% found this document useful (0 votes)
8 views14 pages

19 1 Final

The document is a final exam for CS 320, Spring 2019, consisting of various programming and type theory questions. It includes tasks such as summarizing course learnings, creating problems, discussing garbage collection in programming languages, and writing operational semantics. The exam is closed-book and has specific instructions for answering in Korean if fluent.

Uploaded by

전성진
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views14 pages

19 1 Final

The document is a final exam for CS 320, Spring 2019, consisting of various programming and type theory questions. It includes tasks such as summarizing course learnings, creating problems, discussing garbage collection in programming languages, and writing operational semantics. The exam is closed-book and has specific instructions for answering in Korean if fluent.

Uploaded by

전성진
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 14

Final Exam

CS 320, Spring 2019


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. Students who are fluent in Korean should write answers in Korean.

1) (5pts) Summarize what you learned from this course in one sentence.

2) (5pts) Make your own problem. You do not need to solve the problem.

3) (5pts) Consider four programming languages: C, C++, Java, and Scala. Describe which programming
languages use garbage collection and which do not. Explain pros and cons of garbage collection.

1
4) (5pts) Write the typing rule for the following expression:
{with {x : τ e1 } e2 }

5) (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:

– From space:

– To space:

2
6) (5pts) The following example shows that TVRCFAE has a type soundness bug:

{{withtype {foo {a num} {b num}}


{fun {x : foo} {cases foo x
{a {n} {+ n 3}}
{b {n} {+ n 4}}}}}
{withtype {foo {c (num -> num)} {d num}}
{c {fun {y : num} y}}}}

a) (3pts) Explain how the example shows the type soundness bug in detail.

b) (2pts) When there is a type soundness bug in a language, how can one fix the bug?

7) (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}

3
8) (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.
Do not remove two with expressions.

Γ[α] ` 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}}}

4
9) (10pts) Consider the following language:

e ::= n τ ::= num


| x | (τ -> τ )
| (fun (x:τ ) e) | {l:τ , ..., l:τ }
| (e e)
| {l=e, ..., l=e}
| e.l

with the following typing rules for records:

Γ ` e1 : τ1 · · · Γ ` en : τn Γ ` e : {· · · , l:τ, · · · } Γ ` e : τ 0 τ 0 <: τ
Γ ` {l1 =e1 , · · · , ln =en } : {l1 :τ1 , · · · , ln :τn } Γ ` e.l : τ Γ`e:τ

{l1 :τ1 , · · · , ln :τn , l:τ } <: {l1 :τ1 , · · · , ln :τn } τ0 <: τ1 τ1 <: τ2 τ <: τ
τ0 <: τ2

a) (5pts) Show that the following expression is not well-typed:


((fun (x:{a:{b:num,c:num}})
((fun (y:{a:{b:num}}) y.a.b) x))
{a={b=2,c=3}})

b) (5pts) Revise the typing rule(s) to make the above expression well-typed.

5
10) (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 value at the location denoted by the value of e
| 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.

6
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.

7
11) (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 + ] :: κ

∗ [ (e, σ)] :: κ

∗ [v ] :: κ

8
b) σ, κ ` e ⇒ v
∗ n
n 7→ κ ⇓ v
σ, κ ` n ⇒ v
∗ e+e

∗ x

∗ λx. e

∗ ee

∗ withcc x e

9
12) (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 →

σ ` e1 e2 :: κ || s →

(@) :: κ || v :: hλx. e, σi :: s →

(@) :: κ || v :: hκ0 , s0 i :: s →

σ ` withcc x e :: κ || s →

10
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 ::  || 


11
13) (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∗ ) | (C)e
where metavariables C, D, and E range over class names, x ranges over field names and parameter
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

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. The casting “(C)e” is well typed only when the type of e is a subtype of C.

12
14) (10pts) When a programming language provides overloading, multiple function declarations may have
the same name. Consider the following example:

1 toString(x: Int): String = "line 1"


2 toString(x: Bool): String = "line 2"
3 toString(false)

Even though two function declarations on lines 1 and 2 have the same name, it is clear that the one
on line 2 is called on line 3 because of the different parameter types of the functions.
When multiple function declarations may be called for a given function call like the following example:

4 toString(x: Int): String = "line 4"


5 toString(x: Number): String = "line 5"
6 toString(42)

the function declaration that is more specific than all the other function declarations that may be
called for the given function call is called. We say that a function declaration f (x1 : A1 , · · · , xn : An )
is more specific than f (x1 : B1 , · · · , xn : Bn ), if Ai is a subtype of Bi (Ai <: Bi ) for 1 ≤ i ≤ n. We
assume that Int is a subtype of Number. When no single function declaration is more specific than all
the other function declarations that may be called for a given function call, the function call shows an
ambiguous call error.

(a) (5pts) Explain why the following example shows an ambiguous call error:
7 toString(x: Int, y: Number): String = "line 7"
8 toString(x: Number, y: Int): String = "line 8"
9 toString(42, 8)
where both 42 and 8 have type Int.

Add one function declaration to remove the ambiguous call error.

13
(b) (5pts) For simplicity, we assume the following:
∗ Every function has exactly two parameters.
∗ The subtype relation is a parital order:
reflexive (T <: T ),
antisymmetric (T <: S and S <: T implies T = S), and
transitive (T <: S and S <: R implies T <: R).
∗ If a type has two types as its supertypes, then the two supertypes also are in the subtype
relation: if T <: S and T <: R, then S <: R or R <: S.
Now, we will create rules for a set of all the function declarations with the same name in a given
program, which can ensure that there is no ambiguous function call if the rules are satisfied.
Precisely, we want to make the following statement hold:
If a set of all the function declarations with the same name in a given program satisfies
the rules, {m(x11 : T11 , x12 : T12 ) : S1 = e1 , · · · , m(xn1 : Tn1 , xn2 : Tn2 ) : Sn = en } safe,
then evaluation of the following program does not result in an ambiguous call error:

m(x11 : T11 , x12 : T12 ) : S1 = e1


···
m(xn1 : Tn1 , xn2 : Tn2 ) : Sn = en
m(e, e0 )

We formalize the safe rule as follows:

∀(i, j) ∈ {(i, j) : 1 ≤ i < j ≤ n}. Ti1 6= Tj1 ∨ Ti2 6= Tj2


∀(i, j) ∈ {(i, j) : 1 ≤ i < j ≤ n}. (Ti1 , Ti2 ) meet (Tj1 , Tj2 ) wrt {(T11 , T12 ), · · · , (Tn1 , Tn2 )}
{m(x11 : T11 , x12 : T12 ) : S1 = e1 , · · · , m(xn1 : Tn1 , xn2 : Tn2 ) : Sn = en } safe

The first premise prevents functions with the same parameter types. The second premise prevents
ambiguous call errors for functions with different parameter types, and it has three subcases:

Ti1 <: Tj1 Ti2 <: Tj2


(1)
(Ti1 , Ti2 ) meet (Tj1 , Tj2 ) wrt {(T11 , T12 ), ..., (Tn1 , Tn2 )}
Tj1 <: Ti1 Tj2 <: Ti2
(2)
(Ti1 , Ti2 ) meet (Tj1 , Tj2 ) wrt {(T11 , T12 ), ..., (Tn1 , Tn2 )}
Write the 3rd subcase possibly using the following paritial function:
(
T if T <: S
glb(T, S) =
S if S <: T

(Hint: consider the functions and your answer of (a).)

14

You might also like