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...
map
is not tail-recursive because the
result for the head must be consed onto the result of the
recursive call.
- fun tailMap (f, aList) = let fun helper f result nil = result | helper f result (x::xs) = helper f ((f x)::result) xs in reverse (helper f nil aList) end; val tailMap = fn : ('a -> 'b) * 'a list -> 'b list - tailMap ((fn x => x * 2), [4, 5, 6]); val it = [8,10,12] : int list
filter
is not
tail-recursive, for the same reason that map
is
not tail-recursive. Note that the following uses curried
syntax.
- fun tailFilter pred aList = let fun helper result nil = result | helper result (x::xs) = if pred x then helper (x::result) xs else helper result xs in reverse (helper nil aList) end; val tailFilter = fn : ('a -> bool) -> 'a list -> 'a list - tailFilter (fn x => x > 0.0) [1.0, 2.0, ~3.0]; val it = [1.0,2.0] : real list
find
is already tail
recursive --- in the inductive case, the result of the
recursive call is returned directly.
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;
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);