2.(a) fun add_new e S = if not (member e S) then e::S else S; fun delete e [] = [] |delete e (h::t) = if e=h then t else h::(delete e t); fun intersection [] S2 = [] |intersection S1 [] = [] |intersection (h::t) S2 = if member h S2 then h::(union t S2) else (union t S2); fun subset [] S2 = true |subset (h::t) S2 = (member h S2) andalso (subset t S2); fun card [] = 0 |card (h::t) = 1 + (card t); 2.(b) I can write a function called (for example) pair, that given two arguments produces a pair. fun pair x y = (x,y); I can then partially apply it, giving it one argument, such that it always produces a pair with the same first element. For example I can produce a function pair_with. val pair_with = pair e; I can then map this over the set T, giving me all pairs from T that have e as their first element: map pair_with T; I need to do this for all elements in S. Therefore ... fun cartprod [] T = [] |cartprod (x::xs) T = (map (pair x) T) @ (cartprod xs T); 2.(c) By polymorphic we mean that the function is defined for as yet unspecified argument types. For example the functions above (in (a)) could be used over sets of integers, reals, colours, animals, etc. However, the functions in (a) must have arguments that support tests for equality "=" otherwise they will not work. Therefore we could not compute the union of two sets of functions. The function cartprod could be used in such a scenario, allowing us to compute Cartesian product of sets of functions, since it does not depend on tests of equality.