This assignment has two parts. The purpose of the first part is to help you get acclimated to programming in ML by writing many small exercises. The second part, on type checking, will help prepare you for type inference.
Do not define axuiliary functions at top level. Use [[local]] or [[let]]. Do not use any imperative features unless the problem explicitly says it is OK.
All the sample code we show you is gathered in one place online. If it is useful to you, a Linux implementation of Moscow ML is readily available; see the Moscow ML Home Page for more information.
is03 /tmp >> /usr/local/mosml/bin/mosmlc -c warmup.sml is03 /tmp >>Please remember to put your name, login, and time spent in the file.
Solve the following problems:
compound : ('a * 'a -> 'a) -> int -> 'a -> 'aThat ``compounds'' a binary operator [[rator]] so that [[compound rator n x]] is [[x]] if [[n=0]], [[x rator x]] if [[n = 1]], and in general [[x rator (x rator (... rator x))]] where [[rator]] is applied exactly [[n]] times. [[compound rator]] need not behave well when applied to negative integers.
pow : int -> int -> intso that, for example, [[pow 3 2]] evaluates to 9. Hint: take note of the description of [[op]] in Ullman S5.4.4, page 165.
('a * 'b -> 'b) -> 'b -> 'a list -> 'bThey are like the uScheme versions except the ML versions are Curried.
pairfoldr : ('a * 'b * 'c -> 'c) -> 'c -> 'a list * 'b list -> 'cthat applies a three-argument function to a pair of lists of equal length, using the same order as [[foldr]]. Use [[pairfoldr]] to implement [[zip]].
mergesort : ('a * 'a -> bool) -> 'a list -> 'a listYou'll need two auxiliary functions, one to merge and one to sort. You'll also need two base cases for the sort---not just the empty list, but also the list containing one element.
We can use the [[order]] idiom to define a higher-order insertion function by, e.g.,
<
We can use this idea to implement polymorphic sets in which we store the comparison
function in the set itself.
For example,
<
The function [[setFold]] should visit every element of the set exactly
once, in an unspecified order.
Extra credit:
Recall the following problem from the Scheme homework:
Hints:
Consider the class of well-formed
arithmetic computations using the numeral 5.
These are expressions formed by taking the integer literal 5, the
four arithmetic operators +, -, *, and /, and properly placed parentheses.
Such expressions correspond to binary trees in which the internal nodes are operators and
every leaf is a 5.
Write a uScheme program to answer one or more of the following questions:
Write an ML function [[reachable]] of type
('a * 'a -> order) * ('a * 'a -> 'a) list -> 'a -> int -> 'a set
such that [[reachable (Int.compare, [op +, op -, op *, op div]) 5 5]]
computes the set of all integers computable using the given operators
and exactly five 5's.
(You don't have to bother giving the answers to the questions above,
since they're easy to get with [[setFold]].)
My solution is under 20 lines of code, but it makes heavy use of the
[[setFold]], [[nullset]], [[addelt]], and [[pairfoldr]] functions defined earlier.
fun reachable (cmp, operators) five n =
(* produce set of expressions reachable with exactly n fives *)
As far as proof obligations go, you may assume that the initial [[Gamma]] passed to [[typeof]] is well formed. It is your obligation to ensure that every new environment you might build is also well formed. Thus, if you wish to create new environments in your code, you must do so according to the typing rules for well formed environments.
I recommend that you implement a slightly different set of type rules than are in the notes: you should permit an inner binding of a variable name to hide an outer binding of the same name. (This change would complicate the formal notation, but it will simplify your code.)
Hint: solve the problem in steps:
If you want to submit up to 3 test cases to be applied to other people's code, submit them in a file called [[tests]], complete with comments that tell us how to run them.