Lazy list 2026-10-13
A linked list whose future structure is obtained by calling a delayed computation. In Standard ML,
unit -> node delays a computation until demand. Filtering may need to force arbitrarily many rejected elements to produce its next retained element; filtering an infinite list need not produce a result. Delay alone does not imply memoization.// Destination: computer-science.bigb
Let polymorphism 2026-10-14
Let polymorphism gives an eligible
let-bound name a type scheme, allowing fresh instantiation at each use. In the pure Hindley-Milner type system, generalize the inferred type's type variables that are free in that type and not free in the current typing context. The identity function example under type variable meets this condition. A lambda abstraction's parameter receives one monomorphic type shared by its uses. Languages with mutation, such as Standard ML with ML reference types, need additional restrictions on generalization. ML exception type 2026-10-13
In Standard ML,
exn is an extensible datatype of exception packets. Fresh declarations introduce constructors, optionally with payloads; rebinding can alias an existing constructor; raise propagates a packet and handle performs dynamic pattern-based recovery.// Target: computer-science.bigb
Past exam of the mathematics course of the University of Cambridge 2006 ia Paper 5 1 a Solution Created 2026-09-24 Updated 2026-10-14
Use the usual unit-cost model for Standard ML list constructors and fixed-size arithmetic. The input size in the list examples is the number of list elements, rather than the size of the integer entries. Inspecting only the first constructor has constant time complexity:No tail is traversed. The running time is .
sml
fun firstOrZero [] = 0
| firstOrZero (x :: _) = x; Past exam of the mathematics course of the University of Cambridge 2006 ia Paper 5 1 b Solution Created 2026-09-24 Updated 2026-10-14
A Standard ML length function visits each list constructor once:Writing for its time complexity, and . Thus . Arithmetic is treated as unit cost; the example concerns list traversal rather than arbitrary-precision arithmetic.
sml
fun length [] = 0
| length (_ :: xs) = 1 + length xs; Past exam of the mathematics course of the University of Cambridge 2006 ia Paper 5 6 a i Solution Created 2026-09-24 Updated 2026-10-14
These Standard ML declarations separate the three evaluation and mutation models:The ordinary linked list is immutable and its spine is built eagerly. A lazy list is a delayed function producing the next constructor, with another delayed function for its tail; it can describe an infinite stream without constructing it in advance. A mutable list uses an ML reference type cell for both the root link and every tail link. Updating those cells can remove nodes, including the original head. This lazy list representation delays evaluation but does not automatically implement memoization; repeated forcing can repeat work or effects.
sml
datatype 'a olist = ONil | OCons of 'a * 'a olist;
datatype 'a lnode = LNil | LCons of 'a * (unit -> 'a lnode);
type 'a llist = unit -> 'a lnode;
datatype 'a mnode = MNil | MCons of 'a * 'a mnode ref;
type 'a mlist = 'a mnode ref; Past exam of the mathematics course of the University of Cambridge 2006 ia Paper 5 6 b Solution Created 2026-09-24 Updated 2026-10-14
Represent a binary search tree by:Assume the provided For equality-type values, call
sml
datatype ('k, 'v) dict = Empty
| Branch of ('k, 'v) dict * 'k * 'v * ('k, 'v) dict;lookup d key returns NONE or SOME value, and update d (key, value) returns the updated binary search tree. Traverse the first dictionary, retaining only a key with the same value in the second:sml
fun intersection equal d1 d2 =
let
fun visit Empty result = result
| visit (Branch (left, key, value, right)) result =
let
val r1 = visit left result
val r2 =
case lookup d2 key of
NONE => r1
| SOME other =>
if equal (value, other)
then update r1 (key, value)
else r1
in
visit right r2
end
in
visit d1 Empty
end;intersection (op =) d1 d2. An explicit value comparison parameter also handles values for which Standard ML does not define built-in equality. This distinguishes absent keys from defined values without reserving a sentinel value.Every inserted entry belongs to both input dictionaries with the same value, so the result agrees with each. Conversely, each common equal-valued entry is visited in
d1, found in d2, and inserted. Any dictionary agreeing with both can contain only those entries. Thus the result is exactly the largest common dictionary, not merely an intersection of key sets. If d1 has entries, lookup height is , and maximum result-tree height during insertion is , the time complexity is for constant-cost comparisons. Logarithmic heights require a balancing assumption; an ordinary unbalanced binary search tree can have linear height. Past exam of the mathematics course of the University of Cambridge 2007 ia Paper 5 5 a i Solution Created 2026-09-24 Updated 2026-10-14
Assuming The Standard ML handler in the printed function belongs to the
p is an ordinary total Boolean predicate, replace success by true and the search's failure exception by false:fun gordonPlain p Lf = true
| gordonPlain p (Br (x, left, right)) =
p x andalso
(gordonPlain p left orelse gordonPlain p right);else expression: it tries the left subtree and, only if that search raises Blair, tries the right. It does not catch a failing label test at the current node. This scope follows the Standard ML grammar, Appendix B. Short-circuit andalso rejects the current label before visiting either child; short-circuit orelse visits the right child only after the left search fails. Structural induction on the binary tree proves that tony returns true exactly when gordonPlain does, and otherwise raises the exception converted by gordon to false. The exception-free test is the root predicate conjoined with the disjunction of the two subtree tests.The total-predicate assumption matters: if
p itself raises Blair, the original handler can catch it, whereas an implementation with no exception handling cannot in general convert that event to a Boolean result. The displayed replacement implements the intended Boolean tree property, not an exception-catching wrapper for arbitrary exceptional predicates. Past exam of the mathematics course of the University of Cambridge 2007 ia Paper 5 6 a Solution Created 2026-09-24 Updated 2026-10-14
An ML reference type Both dereferences now give one. A reference's stored type remains fixed; the value restriction prevents allocating one unrestricted polymorphic cell and then using incompatible instantiations.
'a ref describes a mutable cell holding a value of type 'a. The operations are ref : 'a -> 'a ref for allocation, ! : 'a ref -> 'a for dereferencing and := : 'a ref * 'a -> unit for assignment. An immutable variable binding can name a mutable cell; assigning to the cell does not change what the binding denotes. Two names may alias the same cell, so an update through either is visible through the other.val counter = ref 0;
val alias = counter;
counter := !counter + 1;Imperative programming uses sequencing References provide mutable state; sequencing, conditionals and loops control its updates.
(e1; e2; ...; en) to perform effects left to right, with the final expression supplying the result. Conditional expressions choose one branch. while condition do body repeatedly checks a Boolean condition and performs a unit-valued body, returning () on termination. Standard ML has no required primitive for loop, but recursion or a reference with while supplies one. For example:fun sumTo n =
let val i = ref 1
val total = ref 0
in
while !i <= n do
(total := !total + !i; i := !i + 1);
!total
end;