Past exam of the computer science course of the University of Oxford 2015 Probability and computing 2 a Solution by
Codex 0 2026-10-31
For each of the balls, let be the indicator random variable that ball survives the round of uniform balls-in-bins allocation. Condition on its chosen bin. Each of the other balls avoids that bin with probability , independently, so the probability that ball is served is . Hence, for ,We used linearity of expectation to sum the indicator random variables; their mutual independence is unnecessary. For or , the next count is zero. This states the boundary cases without an ambiguous when .
Past exam of the computer science course of the University of Oxford 2015 Probability and computing 1 g Solution by
Codex 0 2026-10-31
The independence of and permits factoring the expectation of the product . The moment-generating function of a binomial distribution from the previous part therefore givesThis is the moment-generating function of . Both moment-generating functions are finite on a neighbourhood of zero, so the uniqueness theorem for moment-generating functions identifies the probability distribution:The common success probability and independence are both used in this argument.
Past exam of the computer science course of the University of Oxford 2015 Probability and computing 1 f Solution by
Codex 0 2026-10-31
For with binomial distribution , where is a nonnegative integer and , use its probability mass function and the binomial theorem:This moment-generating function of a binomial distribution is finite for every real , since the random variable has finite support. The formula also includes the degenerate cases , and .
Past exam of the computer science course of the University of Oxford 2015 Probability and computing 1 e Solution by
Codex 0 2026-10-31
Choose a positive integer-valued random variable with probability mass functionThese masses are positive. They sum to one because the partial fraction decompositionmakes their sum a telescoping series with value . Its expectation is another telescoping series:By contrast, since and for , its second moment satisfiesThe comparison uses the divergent harmonic series. To check the variance directly, for we have , so the corresponding tail of also diverges. ThusHere “unbounded” means infinite variance for this single probability distribution.
Past exam of the computer science course of the University of Oxford 2015 Probability and computing 1 d Solution by
Codex 0 2026-10-31
Let be the result of roll , so . Each has the uniform distribution on a finite set , givingand hence variance . The rolls are independent, so linearity of expectation and variance additivity for independent random variables giveAll the required moments are finite. Taking in Chebyshev's inequality now yieldsThis is an upper bound, rather than an exact tail probability.
Past exam of the computer science course of the University of Oxford 2015 Probability and computing 1 c Solution by
Codex 0 2026-10-31
Chebyshev's inequality assumes a real random variable with finite expectation and finite variance . For every real ,No independence assumption is needed. Applying Markov's inequality to the nonnegative random variable proves the formula, including the zero-variance case.
Past exam of the computer science course of the University of Oxford 2015 Probability and computing 1 b Solution by
Codex 0 2026-10-31
For a real random variable with finite expectation , its variance isWhen the second moment is finite, expansion and linearity of expectation give . The definition also permits infinite variance when the expectation is finite but the second moment is infinite.
Past exam of the computer science course of the University of Oxford 2015 Probability and computing 1 a Solution by
Codex 0 2026-10-31
The expectation of a real random variable on a probability space is its integral against the probability measure:For a discrete random variable, this becomes ; for a random variable with probability density function , it becomes . A finite expectation requires , making an integrable random variable. An extended expectation can also be defined when just one of the positive and negative parts has finite expectation; the indeterminate difference is not allowed.
Past exam of the computer science course of the University of Oxford 2015 Principles of programming languages 3 d Solution by
Codex 0 2026-10-31
Add
Fixes [Ident] [Expr] to the abstract syntax tree. For the stipulated nonempty, equally long lists of distinct names and lambda abstractions, define all programming closures against one common extended semantic environment:eval (Fixes xs es) rho = result (head vs)
where
rho' = extend rho (zip xs vs)
vs = map (\e -> close e rho') esExpanding the auxiliary function, if ,Every body can therefore call every member of the family, including itself. Constructing the family performs no body computations in the arbitrary computational monad. As in part (c), host lazy evaluation ties the recursive semantic environment; a monadic fixed-point operator is unnecessary.
For example, with two bodies implementing evenness and oddness, respectively, each programming closure sees both names in . Returning the first programming closure still retains access to the second. Building each programming closure in an independently extended old semantic environment would lose this mutual recursion. For , the definition agrees with
Fix. Past exam of the computer science course of the University of Oxford 2015 Principles of programming languages 3 c Solution by
Codex 0 2026-10-31
Add the abstract syntax tree alternative
Fix Ident Expr. Its syntactic sugar expansion and the semantic equations from part (a) givewhere and . The final step uses left identity from the monad laws and the lookup rule for the newly bound identifier.eval (Fix x e@(Lambda xs body)) rho = result v
where
rho' = extend rho [(x,v)]
v = close e rho'Equivalently, spelling out programming closure construction,The result is a recursive closure, not the result of calling its body. Its self-binding is visible inside that body but does not extend the caller's surrounding semantic environment.
Past exam of the computer science course of the University of Oxford 2015 Principles of programming languages 3 b Solution by
Codex 0 2026-10-31
The equivalence holds for every lawful computational monad with the semantic equations above. In particular, effects in are neither discarded nor evaluated twice. Fix an initial semantic environment , and writeExpanding
Let and Val givesThe two steps use associativity and left identity from the monad laws.For the application, evaluating the lambda abstraction yields
result c, where the programming closure satisfies . The singleton argument evaluator reduces toUse left identity to remove the initial result c, then associativity and left identity again:Consequently,The argument relies on the lambda abstraction itself being effect-free, as specified in part (a), and on using the same semantic environment for on each side. No commutativity of effects is assumed. In particular, the proof applies to state monads, exceptions and continuation monads, not merely to the identity monad. Past exam of the computer science course of the University of Oxford 2015 Principles of programming languages 3 a Solution by
Codex 0 2026-10-31
Use programming closures that receive evaluated arguments and return a computation in the chosen computational monad. A sufficient core of the semantic value domain is:
data Value = IntVal Integer
| BoolVal Bool
| Function ([Value] -> M Value)Additional constructors may represent the other built-in values. Assume a semantic environment abstract data type with operations
lookupEnv :: Env -> Ident -> Value and extend :: Env -> [(Ident,Value)] -> Env. The latter simultaneously adds the listed bindings, shadowing old bindings. Parameter names in one binding list are distinct, and calls have the expected arity.Define programming closure construction separately; it does not run the body:
close :: Expr -> Env -> Value
close (Lambda xs body) rho =
Function (\args -> eval body (extend rho (zip xs args)))
apply :: Value -> [Value] -> M Value
apply (Function f) args = f argsThe four expression forms have the following semantic equations. Function position is evaluated first, followed by argument expressions from left to right:
eval :: Expr -> Env -> M Value
eval (Variable x) rho = result (lookupEnv rho x)
eval (Apply e es) rho =
bind (eval e rho) (\f ->
bind (evalArgs es rho) (\args -> apply f args))
eval e@(Lambda xs body) rho = result (close e rho)
eval (Let d body) rho =
bind (defn d rho) (\rho' -> eval body rho')
evalArgs :: [Expr] -> Env -> M [Value]
evalArgs [] rho = result []
evalArgs (e:es) rho =
bind (eval e rho) (\v ->
bind (evalArgs es rho) (\vs -> result (v:vs)))The two definition forms are:
defn :: Defn -> Env -> M Env
defn (Val x e) rho =
bind (eval e rho) (\v -> result (extend rho [(x,v)]))
defn (Rec x e@(Lambda xs body)) rho = result rho'
where
rho' = extend rho [(x,v)]
v = close e rho'The ordinary definition evaluates its right-hand side in the old semantic environment; its own name is not yet bound there. The recursive definition creates a recursive closure in the extended semantic environment containing itself. Because the right-hand side is a lambda abstraction, constructing that programming closure does not evaluate its body. Haskell's lazy evaluation can tie this recursive data structure without requiring any extra fixed-point operation from the arbitrary computational monad.
Lexical scope is explicit: calling a programming closure extends the defining semantic environment, and its parameters shadow bindings in that semantic environment. The six requested constructs are therefore covered by
Past exam of the computer science course of the University of Oxford 2015 Principles of programming languages 2 e Solution by
Codex 0 2026-10-31
Represent a binary semaphore by a two-element list containing the addresses of its busy flag and its waiting FIFO queue. A blocked continuation belongs to the waiting FIFO queue, not the scheduler's runnable FIFO queue. These definitions extend the
FunMem scheduler from the preceding part:val semaphore() =
let val busy = new() in
let val waiting = new() in
busy := false; waiting := nil; busy : waiting : nil;
val acquire(s) =
let val busy = head(s) in
let val waiting = head(tail(s)) in
if !busy then
callcc(lambda (blocked)
waiting := append(!waiting,blocked:nil); dispatch())
else (busy := true; nil);
val release(s) =
let val busy = head(s) in
let val waiting = head(tail(s)) in
if !waiting = nil then (busy := false; nil)
else let val next = head(!waiting) in
waiting := tail(!waiting); enqueue(next); nilA newly created semaphore is free. Acquiring it while free marks it busy and immediately returns
nil. Acquiring it while busy captures the remainder of the caller, appends that continuation to the waiting FIFO queue, and dispatches a runnable computation. No runnable copy of the blocked caller is retained.When a waiting caller exists,
release keeps the busy flag true: the released permit is reserved for that caller. It removes exactly one waiting continuation and appends it to the scheduler's runnable FIFO queue. It does not invoke dispatch, so the releasing computation keeps running. A newcomer cannot steal the reserved permit during the interval before the released caller resumes. That caller's captured continuation resumes after acquire with nil, already possessing the permit.These are FIFO semaphores; the question only requires selecting one waiter, so choosing the oldest is a valid stronger discipline. The updates contain no suspension except at the explicit blocking point, making them atomic relative to this cooperative multitasking scheduler. As allowed in the paper, invalid releases and executions in which every remaining computation is blocked need no error handling; the latter are deadlocks, not a way to make progress. Past exam of the computer science course of the University of Oxford 2015 Principles of programming languages 2 d Solution by
Codex 0 2026-10-31
Keep a FIFO queue of runnable continuations in shared computer memory. Removing a continuation from its head transfers control with
nil; suspending a runnable computation appends its continuation at the rear. A single scheduler group also needs a terminal continuation so that finishing the last computation cannot return through an obsolete invocation of fork.The following is
FunMem, including the shared initialization and helper definitions. run(main) starts a scheduler group; nested fork calls use that same group.val ready = new(); ready := nil;
val stop = new();
rec append(xs,ys) =
if xs = nil then ys else head(xs) : append(tail(xs),ys);
val enqueue(k) =
ready := append(!ready,k:nil); nil;
val dispatch() =
if !ready = nil then withc(!stop,nil)
else let val k = head(!ready) in
ready := tail(!ready); withc(k,nil);
val run(main) =
callcc(lambda (done)
stop := done; ready := nil;
main(); dispatch());
val fork(f) =
callcc(lambda (parent)
enqueue(parent); f(); dispatch());
val yield() =
callcc(lambda (current)
enqueue(current); dispatch())At
fork, the parent is queued before f() starts. The child runs immediately. Its ordinary return value is ignored by sequencing into dispatch(). At yield, the current computation joins the rear, then the oldest runnable computation is removed from the front. If there was no other runnable computation, these operations select the just-captured continuation, so the caller resumes immediately with nil.The invariant is that each suspended runnable computation has exactly one entry in
ready, ordered by the time it most recently became suspended and runnable. A running computation is absent from that FIFO queue. Neither appending nor removing an entry suspends, so these operations are indivisible relative to this cooperative multitasking scheduler. Completing a child removes the child from consideration permanently; it is never enqueued by its completion wrapper.For the paper's example, call the initial computation and the forked computation . The FIFO queue and writes evolve as follows:
Thus the observable list, read after the scheduler group finishes, isThe scheduler exit is used only when no runnable continuations remain. A main computation can place its desired final observable value in shared computer memory and read it after
run returns. This wrapper also permits already-forked computations to finish if the initial computation finishes before them. Each run creates one active scheduler group; calls of run are not nested. Past exam of the computer science course of the University of Oxford 2015 Principles of programming languages 2 c Solution by
Codex 0 2026-10-31
Capturing a continuation retains the destination, while the computer memory is supplied when that destination is eventually invoked. The required Haskell definitions are:
callcc :: (Cont a -> M a) -> M a
callcc f k s = f k k s
withc :: Cont a -> M a -> M a
withc saved p _current s = p saved s
callccPrim :: [Value] -> M Value
callccPrim [Function f] =
callcc (\k -> f [Continuation k])
withcPrim :: [Value] -> M Value
withcPrim [Continuation k,v] = withc k (result v)In
callcc, the handler f k initially runs with the same current continuation k. If it returns normally, its result goes there. If it invokes withc with a saved continuation, the current destination is discarded. In particular,The primitive interface receives values, because the surrounding call-by-value interpreter has already evaluated its arguments. Thus the expression supplied as the second argument of withc is evaluated once, before withcPrim transfers its value. Wrapping that value with result implements precisely the remaining transfer; the primitive must not try to evaluate it a second time. Neither operation restores a saved snapshot of computer memory. Past exam of the computer science course of the University of Oxford 2015 Principles of programming languages 2 b Solution by
Codex 0 2026-10-31
Apply the memory interface before invoking the supplied continuation:
get :: Location -> M Value
get a k s = k (contents s a) s
put :: Location -> Value -> M ()
put a v k s = k () (update s a v)
new :: M Location
new k s = let (a,s') = fresh s in k a s'A read preserves computer memory; a write changes it but returns the unit type value; an allocation uses the updated computer memory returned by
fresh. The continuation always receives the latest computer memory: Past exam of the computer science course of the University of Oxford 2015 Principles of programming languages 2 a Solution by
Codex 0 2026-10-31
The continuation receives both the computed value and the current computer memory. Therefore return invokes it with unchanged computer memory, while sequencing installs a continuation that passes the produced value and updated computer memory to the next computation:
result :: a -> M a
result x k s = k x s
bind :: M a -> (a -> M b) -> M b
bind p f k s = p (\x s' -> f x k s') sFor left identity, expand the two definitions:For right identity,For associativity, both groupings reduce to the same expression:By function extensionality, these establish all three monad laws:
Past exam of the computer science course of the University of Oxford 2015 Principles of programming languages 1 g Solution by
Codex 0 2026-10-31
Fix an answer type and let the continuation return its answer inside the base computational monad:
type ContT m a = (a -> m Answer) -> m Answer
result :: Monad m => a -> ContT m a
result x k = k x
bind :: Monad m => ContT m a -> (a -> ContT m b) -> ContT m b
bind p f k = p (\x -> f x k)The continuation monad transformer changes the continuation supplied to
p: it first runs f on the produced value, then uses the original final continuation k. Base sequencing is unnecessary in these two definitions because p already accepts a continuation returning m Answer. The customary lift, if desired, is lift q k = bindM q k. Past exam of the computer science course of the University of Oxford 2015 Principles of programming languages 1 f Solution by
Codex 0 2026-10-31
Expand the two type synonyms to see what survives an exception:In the first order, a failed computation can still produce
(Nothing,s'). The exception handler therefore runs with , including writes made before failure. In the second order, failure produces Nothing, with no returned computer memory. A handler defined by applying the underlying orelse pointwise runs its alternative from the original input computer memory . This gives rollback of this explicit program state for the failed branch.For example, start with a memory location holding , write , fail, and handle the failure by reading that memory location. The first order returns ; the second returns . This rollback concerns the explicit computer memory only: arbitrary effects in the base computational monad are not thereby reversed.A conventional programming language normally retains writes made before an exception is caught. Its mutable computer memory and exception handling therefore correspond more closely to .
Past exam of the computer science course of the University of Oxford 2015 Principles of programming languages 1 e Solution by
Codex 0 2026-10-31
type IdM a = a
result :: a -> IdM a
result x = x
bind :: IdM a -> (a -> IdM b) -> IdM b
bind x f = f xAll three monad laws reduce to substitution in function application. There is no additional program state, failure alternative or continuation layer:
There are unlisted articles, also show them or only show them.
