/* simplified, unbounded polymorphic lists, higher-ordered and inlined functions */ interface list { int length(); void map(function visitor); } interface function { B f(A x); } class nil implements list { public int length() { return 0; } public void map(function visitor) {/* do nothing */} } class cons implements list { private T head; private list tail; public cons(T h, list tl) { head=h; tail=tl; } public T car() { return head; } public list cdr() { return tail; } public int length() { return 1+tail.length(); } public void map(function visitor) { head = visitor.f(head); tail.map(visitor); } } public class pepperoni { public static void main(String[] args) { list l = new cons(2,new cons(3,new cons(5,new cons(7,new nil())))); list s = new cons("ab",new cons("cd",new nil())); System.out.println("length is "+l.length()); function f1, f2; function g1; f1 = new function() { private int u; public int f(int x) { return x+1; } }; f2 = new function() { public int f(int x) { return x*x; } }; g1 = new function() { public String f(String x) { return x+x; } }; function printer = new function() { public int f(int x) { System.out.println(x); return x; } }; l.map(f1); l.map(printer); System.out.println("-----"); l.map(f2); s.map(g1); l.map(printer); } } /* Recall that we tried the "map" trick before - with C# delegates. The problem was that delegates were not parametrically typed - so the "visitor" had to be defined as having type (object)->object. This entailed that it had to explicitly check the runtime type tags of everything it visited, as well as type cast to/from the object superclass. */