Skip to content

Commit

Permalink
Stack-safe evaluation of nested Lazy thunks. Fix #72.
Browse files Browse the repository at this point in the history
  • Loading branch information
jbgi committed Mar 17, 2018
1 parent dedfe22 commit 7c9f84d
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 17 deletions.
18 changes: 10 additions & 8 deletions examples/src/main/java/org/derive4j/example/Bench.java
Expand Up @@ -33,18 +33,20 @@ public class Bench {

public static void main(String[] args) {

// Average time after 200 iterations: 17.869925 ms
timed(() -> List.range(0, COUNT).length());
// Average time after 200 iterations: 44.041202 ms
timed(() -> List.range(0, COUNT).filter(i -> i >= 100000).length());

// Average time after 200 iterations: 26.725065 ms
timed(() -> io.vavr.collection.Stream.range(0, COUNT).length());
// Average time after 200 iterations: 55.995317 ms
timed(() -> io.vavr.collection.Stream.range(0, COUNT).filter(i -> i >= 100000).length());

// Average time after 200 iterations: 24.768288 ms
timed(() -> fj.data.Stream.range(0, COUNT).length());
// Average time after 200 iterations: 49.114037 ms
timed(() -> fj.data.Stream.range(0, COUNT).filter(i -> i >= 100000).length());

// Average time after 200 iterations: 4.771267 ms
timed(() -> java.util.stream.Stream.iterate(0, i -> i + 1).limit(COUNT).reduce(0, (i1, i2) -> i1 + 1));
// Average time after 200 iterations: 6.264414 ms
timed(() -> java.util.stream.Stream.iterate(0, i -> i + 1).limit(COUNT).filter(i -> i >= 100000).reduce(0,
(i1, i2) -> i1 + 1));

// Average time after 200 iterations: 6.911543 ms
timed(() -> Stream.range(0, COUNT).length());
}

Expand Down
10 changes: 6 additions & 4 deletions examples/src/main/java/org/derive4j/example/List.java
Expand Up @@ -84,8 +84,10 @@ public final List<A> append(final List<A> list) {
}

public final List<A> filter(Predicate<A> p) {

return lazy(() -> list(Lists::nil, (h, tail) -> p.test(h) ? cons(h, tail.filter(p)) : tail.filter(p)));
Function<List<A>, List<A>> filter = Lists.cata(
Lists::nil,
(a, tail) -> p.test(a) ? cons(a, lazy(tail)) : lazy(tail));
return lazy(() -> filter.apply(this));
}

public final <B> List<B> bind(Function<A, List<B>> f) {
Expand Down Expand Up @@ -136,7 +138,6 @@ public void accept(A a) {
}

public final int length() {

return foldLeft((i, a) -> i + 1, 0);
}

Expand All @@ -146,7 +147,8 @@ public final <B> B foldRight(final BiFunction<A, Supplier<B>, B> f, final B zero
}

public static void main(String[] args) {
List<Integer> naturals = naturals().take(100);
List<Integer> naturals = naturals().take(20000).filter(i -> i > 10000).take(100);
System.out.println(naturals.length());
List<Integer> naturals2 = naturals().take(100).map(i -> i - 1);
Lists.listShow(Show.intShow).println(naturals);
System.out.println(Lists.listEqual(Equal.intEqual).eq(naturals, naturals));
Expand Down
Expand Up @@ -18,10 +18,12 @@
*/
package org.derive4j.processor;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeVariableName;
Expand Down Expand Up @@ -75,7 +77,10 @@ public DeriveResult<DerivedCodeSpec> derive(AlgebraicDataType adt) {
.map(TypeVariableName::get)
.collect(Collectors.toList());

String className = "Lazy";
ClassName className = ClassName.bestGuess("Lazy");
TypeName lazyTypeName = typeVariableNames.isEmpty()
? className
: ParameterizedTypeName.get(className, typeVariableNames.toArray(new TypeName[0]));
TypeSpec.Builder typeSpecBuilder = TypeSpec.classBuilder(className)
.addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
.addTypeVariables(typeVariableNames)
Expand All @@ -89,11 +94,25 @@ public DeriveResult<DerivedCodeSpec> derive(AlgebraicDataType adt) {
.addModifiers(Modifier.PRIVATE, Modifier.SYNCHRONIZED)
.returns(typeName)
.addCode(CodeBlock.builder()
.addStatement("$T e = expression", lazyArgTypeName)
.beginControlFlow("if (e != null)")
.addStatement("evaluation = e.$L", f0.sam())
.addStatement("expression = null")
.addStatement("$T lazy = this", lazyTypeName)
.beginControlFlow("while (true)")
.addStatement("$T expr = lazy.expression", lazyArgTypeName)
.beginControlFlow("if (expr == null)")
.addStatement("evaluation = lazy.evaluation", f0.sam())
.addStatement("break")
.endControlFlow()
.beginControlFlow("else")
.addStatement("$T eval = expr.$L", typeName, f0.sam())
.beginControlFlow("if (eval instanceof $T)", className)
.addStatement("lazy = ($T) eval", lazyTypeName)
.endControlFlow()
.beginControlFlow("else")
.addStatement("evaluation = eval")
.addStatement("break")
.endControlFlow()
.endControlFlow()
.endControlFlow()
.addStatement("expression = null")
.addStatement("return evaluation")
.build())
.build())
Expand Down

0 comments on commit 7c9f84d

Please sign in to comment.