// CSE341, Fall 2011, Lecture 11 // (This file has not been tested.) interface Func { B m(A x); } interface Pred { boolean m(A x); } class List { T head; List tail; List(T x, List xs) { head = x; tail = xs; } // * the advantage of a static method is it allows xs to be null // -- a more OO way would be a subclass for empty lists // * a more efficient way in Java would be a messy while loop // where you keep a pointer to the previous element and mutate it // -- (try it if you don't believe it's messy) static List map(Func f, List xs) { if(xs==null) return null; return new List(f.m(xs.head), map(f,xs.tail)); } static List filter(Pred f, List xs) { if(xs==null) return null; if(f.m(xs.head)) return new List(xs.head, filter(f,xs.tail)); return filter(f,xs.tail); } // * again recursion would be more elegant but less efficient // * again an instance method would be more common, but then // all clients have to special-case null static int length(List xs) { int ans = 0; while(xs != null) { ++ans; xs = xs.tail; } return ans; } } class ExampleClients { static List doubleAll(List xs) { return List.map((new Func() { public Integer m(Integer x) { return x * 2; } }), xs); } static int countNs(List xs, final int n) { return List.length(List.filter((new Pred() { public boolean m(Integer x) { return x==n; } }), xs)); } }