Programming Languages Practice
Programming Languages Practice
Programming Languages Practice
Practice Examination
May 7, 2013
There are 16 pages in this examination, comprising 5 questions worth a total of 135 points.
You may refer to your personal notes and to the textbook (Practical Foundations of Programming LanguagesPFPL), but to no other person or source, during the examination.
You have 180 minutes to complete this examination.
Please read each question completely before attempting to solve any part.
Please answer all questions in the space provided with the question.
There are two scratch sheets at the end for your use.
Full Name:
Andrew ID:
Question:
Points:
Score:
Conversions
Monads
Dynamic
Parallelism
Concurrency
Total
25
30
30
25
25
135
Types
Units
Expressions
e ::= n | eu | e1 + e2 | e into u
tp n
tp sc
e1 : float(q) e2 : float(q)
e1 + e2 : float(q)
e : float(q) u is a q
e into u : float(q)
tp pl
tp in
The dynamic semantics extends the standard step evaluation judgment e 7 e0 with a conversion
table X, obtaining e 7X e0 . Actual conversions are performed by the auxiliary conversion
judgment X |= 1 u = k u0 which uses the conversion table X to determine that k units of u0
correspond to one unit of u for example we have X |= 1 fathom = 1.8288 meter. The value
judgment is similarly written e valX and holds for expressions of the form n u.
n u valX
e1
7 X e01
e1 + e2
7 X e01 + e2
val n
e1 valX e2 7X e02
e1 + e2 7X e1 + e02
ev pl1
X |= 1 u1 = k u2
ev pl2
ev pl3
n1 u1 + n2 u2 7X (kn1 + n2 )u2
e 7X e0
e into u 7X e0 into u
X |= 1 u0 = k u
ev in1
n u0 into u 7X (kn)u
ev in2
Given this setup, the language so obtained admits the obvious safety properties, which are
omitted.
Page 2
You will now extend this language with a mechanism to add units and conversion factors
(e.g., the Swedish aln, which is equal to 0.5937 meter), with another mechanism to add
new quantities (e.g., time or temperature), and with scalar functions. The resulting language
extension is as follows:
Quantities
q ::= . . . |
Types
Units
u ::= . . . |
Expressions
::= . . . | some(. ) | 1 2
Here, is a quantity variable and is a unit variable. These operators have the following
meaning: letq(..e) creates a new quantity and a measurement unit for for use inside
expression e; letu 1 = e1 in e2 creates a new measurement unit equal to the value of e1 for
use inside expression e2 ; functions have the usual behavior but their argument is restricted to
scalar values. The creation of a new quantity is witnessed by the type some(. ). (If this
works better for you, feel free to do the later parts of this question to gain practice.)
(a) (8 points) Define the static semantics of this language extension by giving typing rules for
letq and letu. Your typing judgment is now ; ` e : , where the context has the form
1 is a q1 , . . . , n is a qn for distinct unit variables i (note that some qj may be a quantity
variable) and the context contains standard typing assumptions of the form x : scalar.
Solution:
(, is a ); ` e :
; ` letq(..e) : some(. )
tp letq
; ` e1 : float(q) (, is a q); ` e2 :
; ` letu 1 = e1 in e2 :
tp letu
(b) (9 points) Define the dynamic semantics of this language extension by giving evaluation
rules for letq and letu. The evaluation judgment is upgraded to hX, ei 7 hX 0 , e0 i, where
X and X 0 are the conversion tables before and after the evaluation step, respectively. You
may extend a conversion table with entries such as 1aln = 0.5937 meter. The rule for
values shall remain unchanged.
Solution:
(#X)
hX, letq(..e)i 7 h(X, 1 = 1), ei
ev letq
hX, e1 i 7 hX 0 , e01 i
hX, letu 1 = e1 in e2 i 7 hX 0 , letu 1 = e01 in e2 i
(#X)
hX, letu 1 = n u in e2 i 7 h(X, 1 = n u), e2 i
Page 3
ev letu1
ev letu2
(c) (4 points) If you were to implement the language so obtained and you wanted to know
how many Swedish alns correspond to 2.3 fathoms using the expression
letu 1aln = 0.5937 meter in 2.3 fathom into aln
you may get the following answer: 3.874 var7062. The scalar part is correct, but what does
the reported unit, var7062, has to do with alns?? Explain what has happened. Recall that
units are stored in the conversion tables at run-time. (If you have time, suggest a way to
fix the problem.)
Solution: Because aln is a bound variable in this expression, it can be -renamed as
needed. The implementation has simply freshened it into some internal identifier,
here var7062.
Optional answer: There is no perfect solution to this problem. One way is to
extend letu with a third argument, a string, that specifies how the unit should be
printed. This brings up a new problem: what if the user mistakenly redefines the
string corresponding to an existing unit (and possibly get some really weird-looking
results)? How do deal with this? Simply turning a blind eye is a recipe for disaster
given that to this day not everybody agrees on how much a gallon holds, and that
there are over a dozen interpretations of what a league is. Given this confusing reality,
the safest solution may be for an implementation to raise a warning (or an error) if
unit names get redefined.
(d) (4 points) Define an expression of type some(.float() float()) that converts any Fahrenheit temperature into Celsius. The conversion formula is C = 5/9 F 32. Note that it
is not as simple as it looks and that you are likely to use every construct you have just
introduced in the grammar. (Feel free to write scalars as fractions, e.g., 5/9 for the scalar
corresponding to 5/9.)
Solution:
letq(temp.F.letu 1C = 5/9 F in x : scalar. xF + 32 C)
Page 4
Page 5
a command that writes the private port as being one that (vacuously) writes the public port.
This leads to the following inclusion rule for commands:
` m @ (r, w) r v r0 w0 v w
` m @ (r0 , w0 )
That is, a command that reads at a level may be regarded as reading at any higher level, and
a command that writes at a level may be regarded as writing at any lower level.
Corresponding to the assignment of security levels to commands, we must enrich the type of
suspended commands to record the security level of the encapsulated command. That is, the
type cmd[(r, w)]( ) is the type of suspended commands that yield a value of type and that
have security level (r, w).
` m @ (r, w)
` cmd(m) : cmd[(r, w)]( )
The static semantics is organized so that each command has a principal security level in which
the read level is as small as possible and the write level is as large as possible.
(a) (5 points) State the principal typing rule for the return command, ret(e).
`e:
Solution: ` ret(e) @ (pub, priv)
(b) (5 points) State the most general possible typing rule for the bind command, seq(e; x.m).
Hint: the security level of e may differ from the security level of m. You will need two
premises relating the read and write levels of e to the read and write levels of m.
` e : cmd[(r, w)]( ) , x: ` m 0 @ (r0 , w0 ) r v r0
Solution:
` seq(e; x.m) 0 @ (r0 , w0 )
w0 v w
There are four commands for performing input and output: rdPriv, rdPub, wrPub(e),
and wrPriv(e). The read commands yield a string, and the write commands take a string
as argument and yield type unit.
Here are the principal typing rules for two of these commands:
` rdPub string @ (pub, priv)
` e : string
` wrPriv(e) unit @ (pub, priv)
By the inclusion rule given above these commands may also be given any security level
(r, w)! This corresponds to the idea that there are no confidentiality restrictions on public
reads or private writes.
(c) (5 points) Give the principal typing rule for private reads and public writes. This means
to give the smallest read level and the largest write level possible consistent with the
intended meaning of the security level of each command.
Solution:
` rdPriv string @ (priv, priv)
Page 6
` e : string
` wrPub(e) unit @ (pub, pub)
The essential reason why this language guarantees confidentiality comes down to the following assertion:
The command seq(cmd(rdPriv); x.wrPub(x)) is ill-typed at level (pub, priv).
That is, we cannot perform a private read followed by a public write in a program that is
well-typed at the most general security level (that is, with the least read level and greatest
write level).
Prove the critical case of this assertion by assuming that ` seq(cmd(rdPriv); x.wrPub(x))
@ (pub, priv) is derivable by the typing rule for sequencing, and deriving a contradiction.
(d) (5 points) By inversion of the typing rule for sequencing, these are all of the typing judgements that may be derived from the assumption.
Solution:
1. ` cmd(rdPriv) : cmd[(r, w)](string);
2. ` rdPriv string @ (r, w);
3. , x:string ` wrPub(x) @ (pub, priv), where = unit.
(e) (5 points) Give all of the ordering judgements among security levels that are derivable
from these facts. You will need to invert the sequencing rule, and you will need to take
account of the inclusion rule!
Solution:
1. r v pub and priv v w (from the sequencing rule).
2. priv v r (from the read private rule)
(f) (5 points) Draw a contradiction from the ordering judgements just derived.
Solution: If priv v r, then r = priv, but then r 6v pub.
Page 7
d err
car(d) err
d1 value d2 7 d02
cons(d1 ; d2 ) 7 cons(d1 ; d02 )
d1 value d2 err
cons(d1 ; d2 ) err
d 7 d0
cdr(d) 7 cdr(d0 )
d 7 d0
ifcons(d; d1 ; d2 ) 7 ifcons(d0 ; d1 ; d2 )
d err
cdr(d) err
d err
ifcons(d; d1 ; d2 ) err
Concentrate only on the extensions described above; do not bother with rules governing
the other constructs of Dynamic PCF.
Page 8
Solution:
d is cons (d1 , d2 )
car(d) 7 d1
d is cons (d1 , d2 )
cdr(d) 7 d2
d isnt cons
car(d) err
d value d is cons ( , )
ifcons(d; d1 ; d2 ) 7 d1
cons(d1 ; d2 ) is cons (d1 , d2 )
d isnt cons
cdr(d) err
nil is nil
Recall that Hybrid PCF is an extension of statically typed PCF with a type dyn of dynamic
values. For the purposes of this question, we will further assume that Hybrid PCF has
product and option types. Now we extend Hybrid PCF with two classes, Cons and Nil, of
values of type dyn. The new and cast operations for these classes have the following typing
rules:
` e : dyn
` e : unit
` new[Nil](e) : dyn
` cast[Nil](e) : unit
` e : dyn dyn
` e : dyn
` new[Cons](e) : dyn
` cast[Cons](e) : dyn dyn
The dynamics for these constructs is as in Hybrid PCF:
e value c 6= c0
cast[c](new[c0 ](e)) err
e value
cast[c](new[c](e)) 7 e
(b) (5 points) Give definitions of nil, cons(e1 ; e2 ), car(e) and cdr(e) in Hybrid PCF so that
they implement the dynamics given above and they obey the following typing rules:
` nil : dyn
` e1 : dyn ` e2 : dyn
` cons(e1 ; e2 ) : dyn
` e : dyn
` car(e) : dyn
` e : dyn
` cdr(e) : dyn
Solution:
nil
cons(e1 ; e2 )
car(e)
cdr(e)
:=
:=
:=
:=
new[Nil](hi)
new[Cons](he1 , e2 i)
fst(cast[Cons](e))
snd(cast[Cons](e))
` e : dyn
` as[Cons](e) : opt(dyn dyn)
The dynamics of as[c](e) is given by the following rules (omitting the obvious congruence
rules):
c 6= c0 e value
e value
as[c](new[c](e)) 7 just(e)
as[c](new[c0 ](e)) 7 null
Page 9
(e) (5 points) The solution to the preceding question reveals two redundant dynamic class
checks arising from the casts of values that are known to be of class Cons. Rewrite the
answer to the preceding question to eliminate the redundant checks by taking advantage
of the bound variable of the ifnull elimination form for option types.
Solution:
fix app : dyn dyn dyn is
x : dyn.
y : dyn.
ifnull(as[Cons](x); y;
u.new[Cons](hfst(u), app(snd(u))(y)i))
Page 10
(EF ilter)
The algorithm, written below, works as follows: we first pick a pivot element in this case,
we simply pick the first element in the sequence. In parallel, we then filter the sequence twice,
selecting those elements less than the pivot into the sequence less, and selecting those elements
greater than the pivot into the sequence more. We then compare k to the size of the two
sequences. There are three cases to consider:
the less sequence contains the element we are looking for. In this case we recurse on less.
the pivot is the element we are looking for.
the more sequence contains the element we are looking for. In this case, we recurse on
more, adjusting k appropriately.
Below is the algorithm described above, with snippets of code missing for you to implement
fix selectk : nat seq nat nat is
x : nat seq. k:nat.
let pivot = x[0] in
letpar less = ... and
more = ... in
if k < len(less) then
selectk less k
else
if k < len(x) - len(more) then
pivot
else
selectk more (k - (len(x) - len(more))
(a) (5 points) Give the first piece of missing code, that computes the value of less by selecting
the elements of the sequence less than the pivot.
Solution: f ilter(x; y.y < pivot)
For this problem, assume that the cost of the arithmetic operations (subtraction, comparison) are computed in constant time. We are concerned with the size of the input as related
Page 11
to the length of the sequence of numbers, not of the size of the numbers themselves. Also
consider the input to be a value, that is, a fully computed sequence of numbers.
The running time of this algorithm is dependent on the input.
(b) (5 points) Give an input to selectk that exhibits the worst case running time. Assume
that the filter operation returns the list of filtered elements in the same order as they
appear in the input.
Solution: selectk(seq(0, 1, 2, ..., n 1), n 1)
Let us now consider the expected running time for this algorithm. Let us now assume that
the filter operation returns the list of filtered elements in random order. This, in effect,
will allow us to assume that the expected size of less is equal to the expected size of more.
(c) (5 points) What is the asymptotic work of this algorithm? This is the time needed to
run this algorithm on a single processor. Write, and solve, the recurrence function as a
function of the length of the sequence.
Solution: For some constants k0 , k1 ,
W (0) = k0
W (2n) = k0 + 4nk1 + W (n)
W (n) = O(n)
(d) (5 points) What is the asymptotic depth of this algorithm? This is the time needed to run
this algorithm on an unbounded number of processors. Write, and solve, the recurrence
function as a function of the length of the sequence.
Solution: For some constants k0 , k1 ,
D(0) = k0
D(2n) = k0 + 4k1 + D(n)
D(n) = O(lg(n))
(e) (5 points) What is the parallelizability ratio of this algorithm? What does this imply
about the ability to make use of multiple processors when executing this algorithm?
Solution: The parallelizability ratio is n/lg(n). For a fixed number of processors, p,
this means that we can make efficient use of them for sufficiently large problems, where
n/lg(n) >= p. For a given input size n, this is the maximum number of processors
that can be used to solve this problem efficiently; any extra processors would be forced
to sit idle.
Page 12
? c(a1 ,...,an )
K
P1 7 P10 P2 7
P20
P1 || P2 7 P10 || P20
In other words synchronization is possible only when the receiver has the private key corresponding to the public key used by the sender.
Now that we have encryption in the spi-calculus, we can define Alice and Bobs handshake
protocol as a process P of the form (K, K).c.(PA || PB ), where PA represents Alice, PB
represents Bob. The key pair K, K and channel c are keys and channels well-known to Alice
and Bob over which they may exchange their public keys. While not made explicit in the
question, it is assumed that other principals also know about c and K, and also that after
exchanging public keys, Alice and Bob have some way to verify that those keys actually belong
to each other (such as meeting in person). You are to write the two process calculus expressions,
PA and PB representing Alice and Bob in the protocol described above.
As shown in the protocol description, PA and PB can each be broken down into three phases;
PAi represents what Alice does in phase i, and PBi represents what Bob does in phase i. In
general, each phase for both Alice and Bob consist of a series of name generations (both keys
and channels), synchronous sends, and synchronous receives, though not all of these have to
occur in each phase. For nonces, they can use channel names, though only because channel
names act as fresh, unguessable secrets.
Page 13
Page 14
Scratch Work:
Page 15
Scratch Work:
Page 16