CSE 341: Higher-order functions, solutions to exercises

Solutions to supplemental exercises

  1. For each of map, filter, and find, determine whether it is tail-recursive. Explain why or why not; and if not, write a tail-recursive version. Write a few test expressons to show that your function works properly. (Note that you may have to reverse the elements when you're done processing the list.)

    First, we define the reverse function, which we'll need because the tail recursive conversion often reverses the results:

    fun reverse aList =
        let
            fun helper result nil = result
              | helper result (x::xs) = helper (x::result) xs
        in
            helper nil aList
        end;
    

    Now, we can define the functions...

  2. Rewrite myMap as a hand-curried function (i.e., using explicit fn forms in the body) instead of a function taking a tuple.
    fun myMap f =
        fn aList =>
           case aList of
               nil => nil
             | x::xs => (f x)::(myMap f xs);
    val myMap = fn : ('a -> 'b) -> 'a list -> 'b list
    - myMap (fn x => x * 2) [1, 2, 3];
    val it = [2,4,6] : int list
    

    Rewrite sumList' in a form that exploits currying.

    val sumList' = reduce (op +) 0;
  3. Write the equivalent of map in C++ or Java, using an object with a mapping function as the function parameter.
    interface Function { Object apply(Object o); }
    
    class ListUtils {
       static List map(Function f, List l) {
         List retval = new LinkedList();
         for (Iterator i = l.iterator(); i.hasNext(); ) {
           retval.add(f.apply(i.next()));
         }
         return retval;
       }
    }
    
    // Example usage
    
    class AddPeriod implements Function {
       public Object apply(Object o) {
         return ((String)o) + ".";
       }
    }
    
    List l = new LinkedList();
    l.add("hi");
    l.add("bye");
    List l2 = ListUtils.map(new AddPeriod(), l);