- The function string_to_num defined below uses two auxiliary
functions to convert a string of digits into a non-negative integer.
fun char_to_num c = ord c - ord "0";
fun calc_list ([],n) = n
| calc_list ((fst::rest),n) =
calc_list(rest,10 * n + char_to_num fst);
fun string_to_num s = calc_list(explode s, 0);
For instance, string_to_num "3405" returns the integer,
3405. Unfortunately, calc_list returns a spurious result if the
string contains any non-digits. For instance, string_to_num "3a05"
returns 7905, while string_to_num " 405" returns ~15595.
This occurs because char_to_num will convert any character, not
just digits. We can attempt to fix this by having char_to_num
raise an exception if it is applied to a non-digit.
- Please revise the definition of char_to_num to raise this
exception, and then modify the function string_to_num so that it handles
the exception, returning ~1 if there is a non-digit in the string. You
should make no changes to calc_list.
- Please rewrite these ML functions to provide the same behavior
(including returning ~1 if the string includes a non-digit) as in (a), but
without using exceptions. While you may change any function, try to
preserve as much of the structure of the original program as possible.
- Please do problem 15 on page 241-2 of the text.
- Please do problem 20ab on page 243 of the text.
- As hinted in class, the THUNK's used to support recursion can also
provide direct support for call-by-name parameter passing. Please modify
the environment-based interpreter to use THUNK's to support call-by-name
rather than call-by-value parameter passing. If you don't like your own,
you can use mine, which can be found in
~kim/cs334stuff/ML/ML.interps/Envinterp.sml)
When you evaluate a function call (with a user-defined function), you
should not evaluate the parameter, instead package the (unevaluated) actual
parameter and the current environment into a NameThunk and insert it into
the environment in the same way that you used to insert the value of the
actual parameter into the environment. Make sure that the THUNK is handled
properly when its value is needed. (Hint: Depending on how you handled
THUNK's before you may not need to make any changes to that part of your
code.)
- Please read Chapter 8 of Ullman on ML's module system. ML's
structures provide for encapsulation, signatures take the place of types
for structures, while functors are parameterized structures. The following
abstype definition of a generic stack was given in class.
abstype 'a stack = mkstack of ('a list)
with exception stackUnderflow
val emptyStk : 'a stack = mkstack []
fun push (e:'a) (mkstack(s):'a stack) = mkstack(e::s)
fun pop (mkstack([]):'a stack) = raise stackUnderflow
| pop (mkstack(e::s):'a stack) = mkstack(s):'a stack
fun top (mkstack([]):'a stack) = raise stackUnderflow
| top (mkstack(e::s):'a stack) = e
fun IsEmpty (mkstack([]):'a stack) = true
| IsEmpty (mkstack(e::s):'a stack) = false
end;
- Please write an equivalent structure definition and supply an
appropriate signature for it. Please make sure that the implementation of
stack is hidden to the user. (You should test the construct with your
"balance" program from assn 2.)
- Compare ML's functors, structures, and signatures to Ada's generic
packages. How do they differ? Does either have any advantages over the
other?