(cmin a) is a sort of bounded identity function: it limits its result to not exceed a.

(pair x) is the function that pairs x with its argument.

(equals x) is the function that recognizes x: it returns true whenever it is applied to the value x.

5.4. If (f x) is to be applied to many different values of y, then the second version is more efficient. Binding (f x) to an ML identifier evaluates h(g x) just once. Then the identifier can be called many times without evaluating h(g x) any more.

With the first version of f, calling (f x) immediately returns a function over y, without evaluating h(g x). Every time the resultant function is called, it will evaluate h(g x).

The two declarations also differ in their treatment of exceptions and non-termination. If h(g x) raises an exception or fails to terminate, then (f x) will exhibit the same behaviour under the second declaration. With the first declaration, the behaviour will not occur until (f x) is applied to some y.

5.5. The occurrence of Dict.lookup has type

(string * (real->real)) Dict.t * string -> (real->real)

5.6. Nesting merge inside tmergesort reduces the number of copies of lessequal that must be passed around.

5.8. Sections and curried functions both permit partial application. But sections apply to paired functions rather than curried functions, and secr permits partial application to a function's second argument.

5.9.

secr op@ ["Richard"] takes a list of strings and appends "Richard" as the last element.

secr take ["heed", "of", "yonder", "dog!"], when applied to an integer k from 0 to 4, returns a list consisting of the first k strings of the list above.

secl 3 take, when applied to a list, returns the first 3 elements.

secl ["his", "venom", "tooth"] inter, when applied to a list of strings, returns just those present in the list above.

5.10. With lazy evaluation (or with proper combinators), the second step would be omitted:

S K K 17 ==> K 17 (K 17) ==> K 17 (fn y=>17) ==> 17

5.11. Define [x]E, the abstraction of E over x, by

[x]x = I
[x](M+N) = (+N) o ([x]M) where the occurrence of x is in M
[x](M+N) = (M+) o ([x]N) where the occurrence of x is in N

These are the only cases, since E contains exactly one occurrence of x.

5.12. Replace according to the following law (proved on page 235):

map f (map g xs) = map (f o g) xs

5.13. Note that pred1 and pred2 are exchanged in the function body, since pred2 must be applied before pred1.

infix andf;
fun (pred1 andf pred2) x = pred2 x andalso pred1 x;

5.14.

fun union (xs,ys) = foldr newmem ys xs;

5.15. The new declaration of dotprod is less efficient and arguably less readable than the original one.

5.36. Write k in binary notation as 1BB...B100...0, where the Bs are zeros or ones. This makes it obvious that k = 2**i' * j', where i' is the number of trailing zeros and j' is the number 1BB...B1. Let i=i'+1 and j=(j'+1)/2. Clearly i and j are positive integers and are uniquely determined by k, and pack(i,j) = pack(i'+1, (j'+1)/2) = 2**i' * j' = k.

5.38. Preorder, inorder and postorder are equally unsuitable for infinite trees because it is impossible to traverse the entire left subtree before the right subtree. Replacing append (@) by interleave corrects this problem. Here is a form of preorder. Compare Seq.take(preorder (itr 1), 15) with the binary tree on page 155:

5.40. This is a simple form of best-first search, using a polymorphic distf function for distances. It adds the (known!) distance from the root to the estimated distance to a solution. The estimate must not be greater than the actual distance, or else the search could be incomplete.

5.41. This version terminates the sequence, but is 50% slower than the one presented in the book. Probably the call to Seq.@ is to blame. I'd be grateful to hear of an efficient version that can recognize when there are no more solutions.