This document contains solutions to the sample questions given in Lecture Note 10
val a = 1;
val b = 2; fun f a = a + b; val b = 3; f b; |
the responses of the system are as follows:
val a = 1 : int
val b = 2 : int val f = fn : int -> int val b = 3 : int val it = 5 : int |
The point here is to check that you understand, and can apply, the scoping rules, applied to the bindings of a and b. The exam on Thursday may include let and local declarations, in a similar question.
fun sum [] = 0
| sum (h :: t) = h + sum t fun leaves (Tree(_,[])) = 1 | leaves (Tree(_,ts)) = sum (map leaves ts) |
or
fun leaves (Tree(_,[])) = 1
| leaves (Tree(x,t :: ts)) = leaves t + leaves (Tree(x, ts)) |
Suppose we are interested in trees where an internal node at level n always has exactly n children. Define a function check : ’a Tree ->bool that checks whether a given tree has this property.
The recursion is not straightforward: to check the property for a tree, we must check a slightly different property for its subtrees. We therefor introduce an auxiliary function, checkk, with an extra parameter; checkk k checks that the appropriate property holds for a subtree rooted at level k:
fun length [] = 0
| length (_::t) = 1 + length t fun andl [] = true (* and over a list of booleans *) | andl (h :: t) = h andalso andl t fun checkk k (Tree(_,[])) = true (* nothing to check for a leaf *) | checkk k (Tree(_,ts)) = ((length ts) = k) (* check there are k children *) andalso andl (map (checkk (k+1)) ts) (* subtrees are at level (k+1) *) fun check t = checkk 1 t |
signature EQueue =
sig type Item type Queue val empty : Queue val enq : (Item * Queue) -> Queue val deq : Queue -> (Item * Queue) val menq: (Item list * Queue) -> Queue end |
An implementation of a stack, including this operation, uses the type declaration
type Queue = Item list list
|
the operations empty and menq are implemented as follows:
val empty = []
fun menq(items, q) = items :: q |
fun enq(item, []) = [[item]]
| enq(item, (h :: t)) = (item :: h) :: t (* or, alternatively, [item] :: h :: t *) fun deq((h :: t) :: r) = (h, t :: r) | deq([] :: r) = deq r | deq [] = raise Deq |
The point here is to take care with the types. Since a stack is being represented as a list of lists, we need to make a list, [[item]], whose only member is the singleton list, [item], to represent a stack with one entry. When adding an item to a non-empty stack, we have a choice: we can either add the item to the list at the head of the list of lists, or we can form a new singleton list and add this to the list of lists.
for this implementation?
Notice that, for a conventional stack implementation we would have to implement menq using multiple calls of enq. The complexity would be O(n), where n is the number of items being added in one go.
fun union(a, []) = a
| union([], b) = b | union(ah :: at, bh :: bt) = if ah < bh then ah :: union(at, bh :: bt) else if ah = bh then ah :: union(at, bt) else bh :: union(ah :: at, bt) |
O(n), where n is the sum of the sizes of the sets; there is at most one recursive call for each of these elements.
fun insert (x,[]) = [x]
| insert (x,h :: t) = if x < h then x :: h :: t else if h < x then h :: insert(x,t) else (* x = h *) h :: t |
This is book-work: a similar definition was given in the notes to implement a priority queue.
fun intersect(a, []) = []
| intersect([], b) = [] | intersect(ah :: at, bh :: bt) = if ah < bh then intersect(at, bh :: bt) else if ah = bh then ah :: intersect(at, bt) else intersect(ah :: at, bt) |
This follows the pattern given in the declaration of union.
(C) Michael Fourman 1994-2006