package org.enumerable.lambda.enumerable; import org.enumerable.lambda.Fn1; import org.enumerable.lambda.Lambda; import org.enumerable.lambda.weaving.Version; import org.enumerable.lambda.enumerable.collection.EList; import org.enumerable.lambda.primitives.Fn1ItoI; import org.enumerable.lambda.primitives.Fn2DDtoD; import org.enumerable.lambda.weaving.LambdaLoader; import java.io.PrintStream; import java.util.HashMap; import java.util.List; import java.util.Map; import static java.lang.Math.*; import static java.util.Arrays.asList; import static org.enumerable.lambda.Lambda.λ; import static org.enumerable.lambda.Parameters.*; import static org.enumerable.lambda.enumerable.Enumerable.*; import static org.enumerable.lambda.primitives.LambdaPrimitives.fn; import static org.enumerable.lambda.primitives.LambdaPrimitives.λ; public class EnumerableExample { /** * <i>If you see errors in this file, and not a real 'lambda' character, * ensure that it's opened as UTF-8.</i> * <p> * λ is a set of static methods in {@link Lambda}, used to create new * lambdas, which can take 0 to 3 arguments. There's also an alias, fn, if * you prefer to not deal with any encoding issues. * <p> * The λ character can be easily be inserted using a template, see * {@link Lambda} for an example. */ public void example(PrintStream out) { assert Character.isJavaIdentifierStart('λ'); List<String> strings = asList("malaysia", "thailand", "india", "people's republic of china"); /* * each will evaluate the block for every element in the list. The block * has to be an expression, printf returns a PrintStream which we * ignore. */ each(strings, λ(s, out.printf("Country: %s\n", s))); /* * eachWithIndex binds the second parameter to the current index, we use * the int @LambdaParameter idx here. The local variable map is * effectively final, as it's only accessed once. */ Map<String, Integer> map = new HashMap<String, Integer>(); eachWithIndex(strings, λ(s, idx, map.put(s, idx))); out.println(map); /* * Basic collect expression, s is a String @LambdaParameter. */ List<String> upperCase = collect(strings, λ(s, s.toUpperCase())); out.println(upperCase); /* * Contrived example of both collecting and modifying a local variable * at the same time. StringBuffer#append returns the buffer, so each * element of stringsSoFar will contain the buffer up to that point. */ StringBuffer sb = new StringBuffer(""); List<String> stringsSoFar = collect(strings, λ(s, sb.append(s).toString())); out.println(stringsSoFar); out.println(sb); List<Integer> ints = asList(5, 1, 8, 4, 6, 3, 10, 2, 7, 9); out.println(ints); /* * Squares a list of integers. The @LambdaParameter n is accessed a * total of 3 times during block construction. The first time is to * define a block argument, the two next times to access the first * parameter to Fn1#call(Object). While actually executing n is not * accessed at all, the arg parameter of the new Fn1 is. */ List<Integer> squares = collect(ints, λ(n, n * n)); out.println(squares); /* * Special case of wrapping a block in a java interface * (java.util.Comparator). For a general, proxy based solution, see the * Fn0#as(Class) method. */ List<Integer> sortedDescending = sort(ints, λ(n, m, m - n)); out.println(sortedDescending); /* * Sorts the collection based on the natural order of the result of an * expression. */ List<String> sortedAscending = sortBy(strings, λ(s, s.length())); out.println(sortedAscending); /* * Closing over the variable two. */ int two = 2; List<Integer> odd = select(ints, λ(n, n % two == 1)); out.println(odd); /* * Example of different primitives than int. Demonstrates call to static * method Math.sqrt. */ List<Double> squareRoots = collect(ints, λ(n, sqrt(n))); out.println(squareRoots); /* * This ignores the input collection, returning "hello" for each * element. Collect transforms, so the input type doesn't have to match * the output type. */ List<String> hellos = collect(ints, λ(n, "hello")); out.println(hellos); /* * Rejects elements based on a boolean expression. */ List<Integer> smallerThanFive = reject(ints, λ(n, n >= 5)); out.println(smallerThanFive); /* * Detect and return the first element matching a boolean expression. */ int largerThanFive = detect(ints, λ(n, n > 5)); out.println(largerThanFive); /* * Detect using ifNone, which returns a constant default value. */ int defaultValue = detect(ints, ifNone(-1), λ(n, n > 10)); out.println(defaultValue); /* * Any returns true if any element matches the boolean expression. */ boolean hasSmallerThanFive = any(ints, λ(n, n < 5)); out.println(hasSmallerThanFive); /* * All returns true if all elements match the boolean expression. */ boolean allSmallerThanEleven = all(ints, λ(n, n < 11)); out.println(allSmallerThanEleven); /* * Count is the same as select(..).size() */ int divisableByThree = count(ints, λ(n, n % 3 == 0)); out.println(divisableByThree); /* * Partition is select and reject rolled into one, returning a list with * two collections, [selected, rejected]. * * EList<?> is a normal wrapped java.util.List which implements * IEnumerable, the instance version of Enumerable. */ EList<EList<Integer>> partitioned = partition(ints, λ(n, n % 2 == 0)); out.println(partitioned); /* * Inject accumulates a value over a collection. n is the accumulator * and 0 is the initial value. n is set to the result of the expression * after each evaluation. m is the current element. */ int sum = inject(ints, 0, λ(n, m, n + m)); out.println(sum); /* * Inject without an initial value, requires the collection to be at * least one element or null will be returned. */ int factorial = inject(ints, λ(n, m, n * m)); out.println(factorial); /* * The ternary operator can be used to evaluate more expressions in * certain cases. You can chain more than one, sacrificing readability. */ String longest = inject(strings, λ(s, t, s.length() > t.length() ? s : t)); out.println(longest); /* * A more complex example of using the ternary operator to evaluate * different expressions based on the input. */ String text = inject(ints, "", λ(s, n, s.length() > 0 ? s + ", " + n : s + n)); out.println(text); /* * Partial application, very limited support as the blocks of this * library are primarily meant to support the Enumerable operations. * Also shows that the blocks are compiled into normal Java classes, an * instance of Fn1 here. These can be passed around like any other * instance. */ Fn1<Integer, Integer> add2 = λ(n, m, n + m).partial(2); out.println(add2.call(5)); out.println(add2.call(-5)); /* * You can use function composition to chain functions like this. */ Fn1<Integer, Integer> negatedAdd2 = λ(n, -n).compose(add2); out.println(negatedAdd2.call(4)); /* * Once defined, lambdas can call themselves recursively. */ fib = fn(n, n <= 1 ? n : fib.call(n - 1) + fib.call(n - 2)); out.println(fib.call(10)); List<Integer> moreInts = asList(-1, 0, 1); /* * More demonstration of calling different static methods, Math.abs in * this case. */ Fn1<Integer, Integer> abs = λ(n, abs(n)); List<Integer> absolutes = collect(moreInts, abs); out.println(absolutes); /* * You can use more than one lambda in the same larger expression like * this, using the returned EIterable. */ List<Integer> oddTimesSum = collect(ints, λ(n, n * sum)).select(λ(n, n % 2 == 1)); out.println(oddTimesSum); /* * Parameters (except for the first) can have default values. */ Fn2DDtoD times = λ(x, y = PI, x * y); out.println(times.call(2.0)); /* * Lambda acting as proxy. */ Runnable runnable = λ(out.printf("running...\n")).as(Runnable.class); runnable.run(); /* * Another example of closure, the Fn1 instance can still read and write * the local variable x if we would to pass it along to another scope. */ int x = 3; Fn1<Integer, Integer> closure = λ(n, x + n); out.println(collect(ints, closure)); /* * Shows that local variable changes are visible inside the closure. */ x = 6; out.println(collect(ints, closure)); /* * And finally, setting the local variable from inside a new block. */ λ(n, x = n).call(2); out.println(x); } Fn1ItoI fib; public static void main(String[] args) { LambdaLoader.bootstrapMainIfNotEnabledAndExitUponItsReturn(args); System.out.println("[example] " + Version.getVersionString()); new EnumerableExample().example(System.out); } }