type List { List addToFront(Any); List addToEnd(Any); Any first(); List rest(); Any atIndex(int); Any last(); List drop(int); List take(int); List appendToEnd(List); List appendToFront(List); List reverse(); int length(); bool empty(); List map([Any] -> Any); Any foldl([Any, Any] -> Any, Any); Any foldr([Any, Any] -> Any, Any); List filter([Any] -> bool); } class MTList() : List impl List { List add(Any elt) { return new ConsList(car = elt, cdr = (this : List)); } Any no_elts(int n) { error("The empty list has no elements!"); } Any no_elt() { error("The empty list has no elements!"); } List rest() { error("The empty list has no elements!"); } List drop(int n) { if n == 0 { this : List; } else { error("Attempt to drop elements from an empty list!"); }; } List take(int n) { if n == 0 { this : List; } else { error("Attempt to take elements from an empty list!"); }; } List ret_other(List l) { return l; } List reverse() { return (this : List); } int length() { return 0; } bool empty() { return true; } List map([Any] -> Any f) { return (this : List); } Any fold([Any, Any] -> Any f, Any i) { return i; } List filter([Any] -> bool f) { return (this : List); } export List : add as addToFront, add as addToEnd, no_elt as first, rest, no_elts as atIndex, no_elt as last, drop, take, reverse, ret_other as appendToEnd, ret_other as appendToFront, length, empty, map, fold as foldl, fold as foldr, filter; } class ConsList() : List impl List { init Any car; init List cdr; Any first() { return car; } List rest() { return cdr; } Any atIndex(int n) { if n == 0 { car; } else { cdr.atIndex(n - 1); }; } Any last() { if cdr.empty() { car; } else { cdr.last(); }; } List drop(int n) { if n == 0 { this : List; } else { cdr.drop(n - 1); }; } List take(int n) { if n == 0 { new MTList(); } else { new ConsList(car = car, cdr = cdr.take(n - 1)); }; } List addToFront(Any x) { return new ConsList(car = x, cdr = (this : List)); } List addToEnd(Any x) { return new ConsList(car = car, cdr = cdr.addToEnd(x)); } List appendToFront(List other) { if other.empty() { this : List; } else { new ConsList(car = other.first(), cdr = other.drop(1)); }; } List appendToEnd(List other) { return new ConsList(car = car, cdr = cdr.appendToEnd(other)); } List reverse() { return cdr.reverse().addToEnd(car); } int length() { return 1 + cdr.length(); } bool empty() { return false; } List map([Any] -> Any f) { return new ConsList(car = f(car), cdr = cdr.map(f)); } Any foldl([Any, Any] -> Any f, Any i) { return f(car, cdr.foldl(f, i)); } Any foldr([Any, Any] -> Any f, Any i) { return cdr.foldr(f, f(car, i)); } List filter([Any] -> bool f) { if f(car) { new ConsList(car = car, cdr = cdr.filter(f)); } else { cdr.filter(f); }; } export List : addToFront, addToEnd, first, rest, atIndex, last, reverse, drop, take, appendToEnd, appendToFront, length, empty, map, foldl, foldr, filter; }