// Operations built on top of the IntList class // Examples from Lyn's CS111 Lec. 15, Fri. Nov. 3, 2006 import java.applet.*; public class IntListOps { public static BooleanList BL; // ------------------------------------------------------------------ // ACCUMULATORS: accumulate an answer (back to front) from the // elements of a list. All of the following are an instantiation // of the following template: /* public static (IntList L) { if (isEmpty(L)) { return ; } else { return (head(L), (tail(L))); } } */ // Returns the number of elements in list L. public static int length (IntList L) { if (isEmpty(L)) { return 0; // = 0 (the identity for +) } else { return 1 + length(tail(L)); // (elt,ans) = 1 + ans } } // Returns the sum of the number of elements in list L. public static int sumList (IntList L) { if (isEmpty(L)) { return 0; // = 0 (the identity for +) } else { return head(L) + sumList(tail(L)); // (elt,ans) = elt + ans } } // Returns the product of the number of elements in list L. public static int prodList (IntList L) { if (isEmpty(L)) { return 1; // = 1 (the identity for *) } else { return head(L) * prodList(tail(L)); // (elt,ans) = elt * ans } } // Returns the minimal number in L (or Integer.MAX_VALUE if L is empty) public static int minList (IntList L) { if (isEmpty(L)) { // = Integer.MAX_VALUE // (the identity for Math.min, acts as "positive infinity") return Integer.MAX_VALUE; } else { // (elt,ans) = Math.min(elt, ans) return Math.min(head(L), minList(tail(L))); } } // Returns the maximal number in L (or Integer.MIN_VALUE if L is empty) // Integer.MIN_VALUE acts as "negative infinity" Math.max. public static int maxList (IntList L) { if (isEmpty(L)) { // = Integer.MIN_VALUE // (the identity for Math.max, acts as "negative infinity") return Integer.MIN_VALUE; } else { // (elt,ans) = Math.max(elt, ans) return Math.max(head(L), maxList(tail(L))); } } // Returns true if all the elements of L are positive, and false otherwise. public static boolean areAllPositive (IntList L) { if (isEmpty(L)) { return true; // = true (the identity for &&) } else { // (elt,ans) = (elt > 0) && ans return (head(L) > 0) && areAllPositive(tail(L)); } } // Returns true if at least one elements of L is positive, and false otherwise. public static boolean isSomePositive (IntList L) { if (isEmpty(L)) { return false; // = false (the identity for ||) } else { // (elt,ans) = (elt > 0) || ans return (head(L) > 0) || isSomePositive(tail(L)); } } // Returns a copy of the list L. public static IntList copyList (IntList L) { if (isEmpty(L)) { return empty(); // OR return list; = empty(); } else { // (elt,ans) = prepend(elt,ans), which copies each list node return prepend(head(L), copyList(tail(L))); } } // ------------------------------------------------------------------ // MAPPERS: transform one list to another in an elementwise fashion. // All of the following are an instantiation of the following template: /* public static (IntList L) { if (isEmpty(L)) { return empty(); // OR return list; } else { return prepend((head(L)), (tail(L))); } } */ public static IntList mapSquare (IntList L) { if (isEmpty(L)) { return empty(); } else { return prepend(head(L) * head(L), mapSquare(tail(L))); } } public static IntList mapDouble (IntList L) { if (isEmpty(L)) { return empty(); } else { return prepend(2 * head(L), mapDouble(tail(L))); } } public static IntList mapScale (int s, IntList L) {// need s as additional parameter if (isEmpty(L)) { return empty(); } else { return prepend(s * head(L), mapScale(s, tail(L))); } } public static BooleanList mapIsPositive (IntList L) { if (isEmpty(L)) { return BL.empty(); } else { return BL.prepend(head(L)>0, mapIsPositive(tail(L))); } } public static BooleanList mapIsEven (IntList L) { if (isEmpty(L)) { return BL.empty(); } else { return BL.prepend((head(L)%2)==0, mapIsEven(tail(L))); } } // ------------------------------------------------------------------ // FILTERS: transform one list to another by keeping only those elements // satisfying a predicate. // All of the following are an instantiation of the following template: /* public static IntList (IntList L) { if (isEmpty(L)) { return empty(); // OR return list; } else if (head(L)) return prepend(head(L), (tail(L))); } else { return (tail(L)); } } */ public static IntList filterPositive (IntList L) { if (isEmpty(L)) { return empty(); } else if (head(L) > 0) { return prepend(head(L), filterPositive(tail(L))); } else { return filterPositive(tail(L)); } } public static IntList filterEven (IntList L) { if (isEmpty(L)) { return empty(); } else if ((head(L) % 2) == 0) { return prepend(head(L), filterEven(tail(L))); } else { return filterEven(tail(L)); } } public static IntList filterDivisors (int n, IntList L) { if (isEmpty(L)) { return empty(); } else if ((n%(head(L))) == 0) { return prepend(head(L), filterDivisors(n, tail(L))); } else { return filterDivisors(n, tail(L)); } } //---------------------------------------------------------------------- // GENERATORS: produce lists from non-lists. public static IntList fromTo (int lo, int hi) { // Returns a list of the integers from lo up to hi. if (lo > hi) { return empty(); } else { return prepend(lo, fromTo(lo + 1, hi)); } } //---------------------------------------------------------------------- // Programs written in the "signal processing style" as a composition of // components that produce and consume lists. This illustrates // lists as a modularity mechanism: It allows programs to be // composed out of mix-and-match components. public static int factorial(int n) { return prodList(fromTo(1,n)); } public static int sumOfSquaredEvens (int lo, int hi) { return sumList(mapSquare(filterEven(fromTo(lo,hi)))); } //---------------------------------------------------------------------- // LIST GLUE // Returns a list whose elements are those of L1 followed by those of L2. // The nodes of L1 are copied while those of L2 are shared. public static IntList append(IntList L1, IntList L2) { if (isEmpty(L1)) { return L2; } else { return prepend (head(L1), append(tail(L1), L2)); } } // Returns a list whose elements are those of L followed by i. // The nodes of L are copied and a new node is made for i as well. public static IntList postpend(IntList L, int i) { return append(L, prepend(i, empty())); } //---------------------------------------------------------------------- // LIST REVERSAL // Recursive reverse public static IntList reverse(IntList L) { if (isEmpty(L)) { return L; } else { return postpend(reverse(tail(L)), head(L)); } } // Iterative reverse public static IntList reverseIter(IntList L) { return reverseTail(L, empty()); } public static IntList reverseTail(IntList oldPile, IntList newPile) { if (isEmpty(oldPile)) { return newPile; } else { return reverseTail(tail(oldPile), prepend(head(oldPile),newPile)); } } //---------------------------------------------------------------------- // Main public static void main (String [] args) { if (args.length == 3) { // mapScale TEST ---------------------------------------------------------- if (args[0].equals("mapScale")) { int s = Integer.parseInt(args[1]); IntList L = IntList.fromString(args[2]); System.out.println("mapScale(" + s + ", " + L + ") = " + mapScale(s,L)); // filterDivisors TEST ---------------------------------------------------- } else if (args[0].equals("filterDivisors")) { int n = Integer.parseInt(args[1]); IntList L = IntList.fromString(args[2]); System.out.println("filterDivisors(" + n + ", " + L + ") = " + filterDivisors(n,L)); // fromTo TEST ------------------------------------------------------------ } else if (args[0].equals("fromTo")) { int lo = Integer.parseInt(args[1]); int hi = Integer.parseInt(args[2]); System.out.println("fromTo(" + lo + ", " + hi + ") = " + fromTo(lo,hi)); // sumOfSquareEvens TEST -------------------------------------------------- } else if (args[0].equals("sumOfSquaredEvens")) { int lo = Integer.parseInt(args[1]); int hi = Integer.parseInt(args[2]); System.out.println("sumOfSquaredEvens(" + lo + ", " + hi + ") = " + sumOfSquaredEvens(lo,hi)); // append TEST ------------------------------------------------------------ } else if (args[0].equals("append")) { IntList L1 = IntList.fromString(args[1]); IntList L2 = IntList.fromString(args[2]); System.out.println("append(" + L1 + ", " + L2 + ") = " + append(L1,L2)); // postpend TEST ------------------------------------------------------------ } else if (args[0].equals("postpend")) { IntList L = IntList.fromString(args[1]); int n = Integer.parseInt(args[2]); System.out.println("postpend(" + L + ", " + n + ") = " + postpend(L,n)); } else { System.out.println("unrecongnized list operator: " + args[0]); } } else if (args.length == 2) { if (args[0].equals("factorial")) { int n = Integer.parseInt(args[1]); System.out.println("factorial(" + n + ") = " + factorial(n)); } else { IntList L = fromString(args[1]); // ---------------------------------------------------------------------- // ACCUMULATOR TESTS if (args[0].equals("length")) System.out.println("length(" + L + ") = " + length(L)); else if (args[0].equals("sumList")) System.out.println("sumList(" + L + ") = " + sumList(L)); else if (args[0].equals("prodList")) System.out.println("prodList(" + L + ") = " + prodList(L)); else if (args[0].equals("maxList")) System.out.println("maxList(" + L + ") = " + maxList(L)); else if (args[0].equals("minList")) System.out.println("minList(" + L + ") = " + minList(L)); else if (args[0].equals("areAllPositive")) System.out.println("areAllPositive(" + L + ") = " + areAllPositive(L)); else if (args[0].equals("isSomePositive")) System.out.println("isSomePositive(" + L + ") = " + isSomePositive(L)); else if (args[0].equals("copyList")) System.out.println("copyList(" + L + ") = " + copyList(L)); // ---------------------------------------------------------------------- // MAPPER TESTS else if (args[0].equals("mapSquare")) System.out.println("mapSquare(" + L + ") = " + mapSquare(L)); else if (args[0].equals("mapDouble")) System.out.println("mapDouble(" + L + ") = " + mapDouble(L)); else if (args[0].equals("mapIsPositive")) System.out.println("mapIsPositive(" + L + ") = " + mapIsPositive(L)); else if (args[0].equals("mapIsEven")) System.out.println("mapIsEven(" + L + ") = " + mapIsEven(L)); // ---------------------------------------------------------------------- // FILTER TESTS else if (args[0].equals("filterPositive")) System.out.println("filterPositive(" + L + ") = " + filterPositive(L)); else if (args[0].equals("filterEven")) System.out.println("filterEven(" + L + ") = " + filterEven(L)); // ---------------------------------------------------------------------- // REVERSE TESTS else if (args[0].equals("reverse")) System.out.println("reverse(" + L + ") = " + reverse(L)); else if (args[0].equals("reverseIter")) System.out.println("reverseIter(" + L + ") = " + reverseIter(L)); else System.out.println("unrecongnized list operator: " + args[0]); } } } // ---------------------------------------------------------- // Local abbreviations: these make IntList ops like prepend and friends // work without explicit prefixes (e.g. IntList.prepend) public static IntList empty() { return IntList.empty(); } public static boolean isEmpty (IntList L) { return IntList.isEmpty(L); } public static IntList prepend (int n, IntList L) { return IntList.prepend(n, L); } public static int head (IntList L) { return IntList.head(L); } public static IntList tail (IntList L) { return IntList.tail(L); } public static boolean equals (IntList L1, IntList L2) { return IntList.equals(L1, L2); } public static String toString (IntList L) { return IntList.toString(L); } public static IntList fromString (String s) { return IntList.fromString(s); } }