Project Euler is a list of 178, mathematical problems, that can be solved by computers. They vary in complexity from simple to hard. The goal is to test ShapeLogic's new declarative and functional constructs on real problems and make sure they are terse and intuitive.
Here is the Java file containing the 10 first problems, where each problem will be turned into a junit test: http://shapelogic.googlecode.com/svn/trunk/src/test/java/org/shapelogic/euler/ProjectEuler1Test.java
The best way to get familiar ShapeLogic's new functional constructs is to create a Java project with just this file. All you need for this to run is junit.jar and shapelogic_0.9.jar.
The blog http://scala-blogs.org/2007/12/project-euler-fun-in-scala.html is showing off the strength of Scala to solve some of the problems defined in Project Euler. This is as easy as it gets. The APL, Erlang, Haskell, Mathematica, Perl and Python programmer will surely argue. This is the benchmark by which to measure ShapeLogic's success.
The solution in Scala clearly use less code, but conceptually there is not a big gap in complexity. Especially when you are using Eclipse which will generate the methods you have to override in order to customize the lazy stream constructs. Java is inherently verbose, so it will never be that terse.
This is the assessment based on a few first simple examples, maybe ShapeLogic will buckle under more complex examples.
Generate a stream of natural numbers, can take a start and stop number
A filter that takes an Iterator as input, and an evaluate method.
An accumulator that run through an Iterator and add all the number in it.
NaturalNumberStream naturalNumberStream = new NaturalNumberStream(1,999); ListFilterStream<Integer> filter = new BaseListFilterStream<Integer>(naturalNumberStream) { public boolean evaluate(Integer object) {return object % 3 == 0 || object % 5 == 0;} }; SumAccumulator accumulator = new SumAccumulator(filter); System.out.println(accumulator.getValue());
BaseListStream1<Object,Integer> fibonacci = new BaseListStream1<Object,Integer>(){ { _list.add(1); _list.add(2);} public Integer invoke(Object input, int index) {return get(index-2) + get(index-1);} }; ListFilterStream<Integer> filter = new BaseListFilterStream<Integer>(fibonacci) { public boolean evaluate(Integer object) { return object % 2 == 0; } }; SumAccumulator accumulator = new SumAccumulator(filter) { {_inputElement = 0;} public boolean hasNext(){ return _inputElement < 1000000; } }; System.out.println(accumulator.getPreviousValue()); //Test fails after value go over 1000000
NaturalNumberStream naturalNumberStream = new NaturalNumberStream(2,null); BaseAccumulator<Integer,Long> accumulator = new BaseAccumulator<Integer,Long>(naturalNumberStream) { long theNumber = 317584931803l; {_inputElement = 0;} public Long accumulate(Integer element, Long out) { while (theNumber % element == 0l) { theNumber /= element; } return theNumber; } public boolean hasNext(){ return _inputElement <= theNumber; } }; System.out.println(accumulator.getValue());
NaturalNumberStream naturalNumberStream = new NaturalNumberStream(1,999); BaseListStream2<Integer, Integer, Integer> cartesianProduct = new BaseListStream2<Integer, Integer, Integer>(naturalNumberStream, naturalNumberStream) { public Integer invoke(Integer input0, Integer input1, int index) {return input0 * input1;} }; ListFilterStream<Integer> filter = new BaseListFilterStream<Integer>(cartesianProduct) { public boolean evaluate(Integer object) {return palindrome(object);} }; MaxAccumulator accumulator = new MaxAccumulator(filter); System.out.println(accumulator.getValue());
NaturalNumberStream naturalNumberStream = new NaturalNumberStream(2,20); final PrimeNumberStream primeNumberStream = new PrimeNumberStream(); final AdvanceWhile<Integer> primesUnder20 = new AdvanceWhile<Integer>(primeNumberStream){ @Override public boolean evaluate(Integer input) { return input <= 20; } }; Accumulator<Integer, Map<Integer,Integer> > accumulator = new BaseAccumulator<Integer, Map<Integer,Integer> >(naturalNumberStream) { {_value = new TreeMap<Integer,Integer>();} @Override public Map<Integer,Integer> accumulate(Integer element, Map<Integer,Integer> out) { for (Integer prime: primeNumberStream.getList()) { if (element < prime) break; int rank = rankOfDivisor(element,prime); Integer currentRank = out.get(prime); if (0 < rank && (currentRank == null || currentRank < rank)) out.put(prime,rank); } return out; } }; System.out.println(productWithPower(accumulator.getValue()));
NaturalNumberStream naturalNumberStream = new NaturalNumberStream(1,100); BaseListStream1<Integer, Integer> squaredStream = new BaseListStream1<Integer, Integer>(naturalNumberStream) { public Integer invoke(Integer input, int index) { if (input == null) return null; return input * input; } }; SumAccumulator sumOfSquares = new SumAccumulator(squaredStream); SumAccumulator sumOfNumbers = new SumAccumulator(naturalNumberStream); long result = sumOfNumbers.getValue() * sumOfNumbers.getValue() - sumOfSquares.getValue(); System.out.println(result);
PrimeNumberStream primeNumberStream = new PrimeNumberStream(); long result = primeNumberStream.get(10000); System.out.println(result);
final String inputNumbers = "73167176531330624919225119674426574742355349194934" + "96983520312774506326239578318016984801869478851843" + "85861560789112949495459501737958331952853208805511" + "12540698747158523863050715693290963295227443043557" + "66896648950445244523161731856403098711121722383113" + "62229893423380308135336276614282806444486645238749" + "30358907296290491560440772390713810515859307960866" + "70172427121883998797908792274921901699720888093776" + "65727333001053367881220235421809751254540594752243" + "52584907711670556013604839586446706324415722155397" + "53697817977846174064955149290862569321978468622482" + "83972241375657056057490261407972968652414535100474" + "82166370484403199890008895243450658541227588666881" + "16427171479924442928230863465674813919123162824586" + "17866458359124566529476545682848912883142607690042" + "24219022671055626321111109370544217506941658960408" + "07198403850962455444362981230987879927244284909188" + "84580156166097919133875499200524063689912560717606" + "05886116467109405077541002256983155200055935729725" + "71636269561882670428252483600823257530420752963450"; final int numberLength = inputNumbers.length()-1; BaseListStream0<Integer> inputNumberStream = new BaseListStream0<Integer>(numberLength) { @Override public Integer invoke(int index) { char c = inputNumbers.charAt(index); return Integer.parseInt(""+c); } }; BaseListStream1<Integer, Integer> productStream = new BaseListStream1<Integer, Integer>(inputNumberStream,numberLength) {//XXX you should not need to set length public Integer invoke(Integer input, int index) { if (index<4) return 0; int result = 1; for (int i=index-4; i<=index;i++) {result*=getInput(i);}; return result; } }; MaxAccumulator maxAccu = new MaxAccumulator(productStream); System.out.println(maxAccu.getValue()); assertEquals(new Integer(40824),maxAccu.getValue());
NaturalNumberStream naturalNumberStream = new NaturalNumberStream(1,500); final int[] EMPTY_ARRAY = new int[0]; BaseListStream2<Integer, Integer, int[]> cartesianProduct = new BaseListStream2<Integer, Integer, int[]>(naturalNumberStream, naturalNumberStream) { public int[] invoke(Integer a, Integer b, int index) { int c = 1000 - a - b; if (b<=a) return EMPTY_ARRAY; if (c*c == a*a + b*b) return new int[] {a,b,c}; else return EMPTY_ARRAY; } }; ListFilterStream<int[]> filter = new BaseListFilterStream<int[]>(cartesianProduct) { public boolean evaluate(int[] object) {return EMPTY_ARRAY != object;} }; int[] result = filter.next(); long resultNumber = product(result); System.out.println("result: "+ product(result)); System.out.println("a: " + result[0] + ", b: " + result[1] + ", c: " + result[2]);
PrimeNumberStream primeNumberStream = new PrimeNumberStream(); final AdvanceWhile<Integer> primesUnder1000000 = new AdvanceWhile<Integer>(primeNumberStream){ public boolean evaluate(Integer input) {return input <= 1000000;} }; primeNumberStream.setMaxLast(primeNumberStream.getList().size()-1); //XXX maybe change the accumulator System.out.println("Number of primes under 1000000: " + (primeNumberStream.getList().size()-1)); SumAccumulator sumAccu = new SumAccumulator(primeNumberStream.getList().iterator()); long result = sumAccu.getPreviousValue(); System.out.println(result);