package au.id.zancanaro; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.function.Function; public interface Generator { RoseTree generate(Random random, int size); static Generator pure(T value) { return (random, size) -> RoseTree.pure(value); } default Generator genFlatmap(Function, Generator> f) { return (random, size) -> { RoseTree inner = this.generate(random, size); Generator generator = f.apply(inner); return generator.generate(random, size); }; } default Generator genFmap(Function, RoseTree> f) { return (random, size) -> f.apply(this.generate(random, size)); } @SafeVarargs static Generator tuple(Generator... generators) { return (random, size) -> { @SuppressWarnings("unchecked") RoseTree[] result = (RoseTree[]) new RoseTree[generators.length]; int index = 0; for (Generator generator : generators) { result[index++] = generator.generate(random, size); } return RoseTree.zip(Function.identity(), result); }; } default Generator fmap(Function f) { return (random, size) -> this.generate(random, size).fmap(f); } default Generator flatMap(Function> action) { return this.genFlatmap(rose -> { Generator> generator = (random, size) -> rose.fmap(action).fmap(g -> g.generate(random, size)); return generator.genFmap(RoseTree::join); }); } }