Assignment 1 -- Due 2/25/97

Part A: Not to be turned in

1. Define a function sumsqrs that, given a nonnegative integer n, returns the sum of the squares of the numbers from 1 to n.

2a. Define a function dup which takes an element, e, of any type and returns a tuple with the element duplicated. E.g.,

   dup "ab" = ("ab","ab").
b. Define a function list_dup which takes an element, e, of any type, and a positive number, n, and returns a list with n copies of e. E.g.,
   list_dup "ab" 3 = ["ab","ab","ab"].
Part B: To be turned in

1. Write a function int_to_string which converts an integer (positive or negative) to the string of its digits. Hints: It is easy to write int_to_string if you have a function non_neg_to_string, which converts a non-negative integer to a string. Similarly it is relatively easy to write non_neg_to_string given a function, digit_to_char. Here is a definition of digit_to_char:

   fun digit_to_char (n:int) = chr (n + ord "0");
Use a let clause to hide the auxiliary functions.

2a. Write a function to add two vectors of integers of the same length, represented as lists. That is,

   addv [1,3,5,7] [7,5,3,1] = [8,8,8,8].
b. Write a function which adds any number of vectors of integers of the same length.

Note: If the vectors don't have the same length, you may decide how you would like the function to behave. If you don't specify any behavior at all you will get a warning from the compiler that you have not taken care of all possible patterns.

3a. Recursion is the only means of obtaining looping behavior in ML, but not all recursive programs take the same amount of time to run. Consider, for instance, the following function that raises a number to a power:

   fun exp base power = 
        if power = 0 then 1 else base * (exp base (power-1));
There are more efficient means of exponentiation. First write an ML function that squares an integer, and then using this function design an ML function fastexp which calculates (basepower) for any power >= 0 by the rule
   base0 = 1
   basepower = (base(power/2))2 if m is even
   basepower = base * (base(power-1))    if m is odd
It is easy to blow this optimization and not save any multiplications. Prove the program you implemented is indeed faster than the original by comparing the number of multiplications that must be done for exponent m in the first and second algorithms. (Hint it is easiest to calculate the number of multiplications if the exponent, power, is of the form 2k for the second algorithm. Give the answer for exponents of this form and then try to give an upper bound for the others. Also recall that ML is call-by-value. That is, the argument to a function is evaluated before the call.)

b. A Pascal program corresponding to the fast solution above is as follows:

    function exp(base, power: integer): integer;
    var ans:integer
        ans:= 1;
        while power > 0 do
            if odd(power) then
                    ans := ans*base;
                    power:= power- 1
                    base := base * base;
                    power := power div 2
        exp := ans
Please mimic the translation given in class to convert this Pascal program to ML. (Note you will obtain a different - and slightly more efficient - version of the program than the natural recursive solution in part a.)

4. One can implement binary trees that only store values at the leaves using the datatype declaration

    datatype 'a tree = 
                Leaf of 'a | InternalNode of ('a tree) * ('a tree)
Implement the function samefringe which returns true if two binary trees have the same fringe. The fringe of a binary tree is the ordered list of values that appear at the leaves of the tree (after doing an inorder traversal of the tree). For instance, the fringes of the binary trees

are both 7,4,5,7,6, even though they are different trees.

Hint: You may want to divide the problem into parts, first computing the fringes and then testing them for equality. You can use "=" to test for equality of lists.