Created
October 8, 2018 18:05
-
-
Save jbgi/31b891f00566feb301f8100762ee8511 to your computer and use it in GitHub Desktop.
Derive4J for extensible algebraic data types.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Data | |
interface Exp { | |
interface ExpAlg<E, R> { | |
R Lit(int lit); | |
R Add(E e1, E e2); | |
} | |
<R> R accept(ExpAlg<Exp, R> alg); | |
} | |
@Data | |
interface ExpMul { | |
interface ExpMulAlg<E, R> extends Exp.ExpAlg<E, R> { | |
R Mul(E e1, E e2); | |
} | |
<R> R accept(ExpMulAlg<ExpMul, R> alg); | |
static Function<Exp, ExpMul> fromExp() { | |
ExpMulAlg<ExpMul, ExpMul> factory = ExpMuls.factory(); | |
return Exps.cata(factory, ExpMuls::lazy); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Generated by Derive4J: | |
import java.lang.Integer; | |
import java.lang.Override; | |
import java.util.Optional; | |
import java.util.function.Function; | |
import java.util.function.Supplier; | |
final class ExpMuls { | |
private static final ExpMul.ExpMulAlg<ExpMul, Optional<Integer>> litGetter = ExpMuls.alg((lit) -> Optional.of(lit), | |
(e1, e2) -> Optional.empty(), | |
(e1, e2) -> Optional.empty()); | |
private static final ExpMul.ExpMulAlg<ExpMul, Optional<ExpMul>> e1Getter = ExpMuls.alg((lit) -> Optional.empty(), | |
(e1, e2) -> Optional.of(e1), | |
(e1, e2) -> Optional.of(e1)); | |
private static final ExpMul.ExpMulAlg<ExpMul, Optional<ExpMul>> e2Getter = ExpMuls.alg((lit) -> Optional.empty(), | |
(e1, e2) -> Optional.of(e2), | |
(e1, e2) -> Optional.of(e2)); | |
private static final ExpMul.ExpMulAlg<ExpMul, ExpMul> factory = new LambdaExpMulAlg<>(ExpMuls::Lit, ExpMuls::Add, ExpMuls::Mul); | |
private ExpMuls() { | |
} | |
public static <R> ExpMul.ExpMulAlg<ExpMul, R> alg(Function<Integer, R> Lit, | |
AddMapper<ExpMul, R> Add, MulMapper<ExpMul, R> Mul) { | |
return new LambdaExpMulAlg<>(Lit, Add, Mul); | |
} | |
public static ExpMul Lit(int lit) { | |
return new Lit(lit); | |
} | |
public static ExpMul Add(ExpMul e1, ExpMul e2) { | |
return new Add(e1, e2); | |
} | |
public static ExpMul Mul(ExpMul e1, ExpMul e2) { | |
return new Mul(e1, e2); | |
} | |
public static ExpMul lazy(Supplier<ExpMul> expMul) { | |
return new Lazy(expMul); | |
} | |
public static CasesMatchers.TotalMatcher_Lit cases() { | |
return CasesMatchers.totalMatcher_Lit; | |
} | |
public static CaseOfMatchers.TotalMatcher_Lit caseOf(ExpMul expMul) { | |
return new CaseOfMatchers.TotalMatcher_Lit(expMul); | |
} | |
public static Optional<Integer> getLit(ExpMul expMul) { | |
return expMul.accept(litGetter); | |
} | |
public static Optional<ExpMul> getE1(ExpMul expMul) { | |
return expMul.accept(e1Getter); | |
} | |
public static Optional<ExpMul> getE2(ExpMul expMul) { | |
return expMul.accept(e2Getter); | |
} | |
public static Function<ExpMul, ExpMul> setLit(Integer newLit) { | |
return modLit(__ -> newLit); | |
} | |
public static Function<ExpMul, ExpMul> modLit(Function<Integer, Integer> litMod) { | |
ExpMul.ExpMulAlg<ExpMul, ExpMul> expMulAlg = org.derive4j.example.algebras.ExpMuls.alg((lit) -> Lit(litMod.apply(lit)), | |
ExpMuls::Add, | |
ExpMuls::Mul); | |
return expMul -> expMul.accept(expMulAlg); | |
} | |
public static Function<ExpMul, ExpMul> setE1(ExpMul newE1) { | |
return modE1(__ -> newE1); | |
} | |
public static Function<ExpMul, ExpMul> modE1(Function<ExpMul, ExpMul> e1Mod) { | |
ExpMul.ExpMulAlg<ExpMul, ExpMul> expMulAlg = org.derive4j.example.algebras.ExpMuls.alg(ExpMuls::Lit, | |
(e1, e2) -> Add(e1Mod.apply(e1), e2), | |
(e1, e2) -> Mul(e1Mod.apply(e1), e2)); | |
return expMul -> expMul.accept(expMulAlg); | |
} | |
public static Function<ExpMul, ExpMul> setE2(ExpMul newE2) { | |
return modE2(__ -> newE2); | |
} | |
public static Function<ExpMul, ExpMul> modE2(Function<ExpMul, ExpMul> e2Mod) { | |
ExpMul.ExpMulAlg<ExpMul, ExpMul> expMulAlg = org.derive4j.example.algebras.ExpMuls.alg(ExpMuls::Lit, | |
(e1, e2) -> Add(e1, e2Mod.apply(e2)), | |
(e1, e2) -> Mul(e1, e2Mod.apply(e2))); | |
return expMul -> expMul.accept(expMulAlg); | |
} | |
public static <R> Function<ExpMul, R> cata(Function<Integer, R> Lit, AddMapper<R, R> Add, | |
MulMapper<R, R> Mul, Function<Supplier<R>, R> delay) { | |
return cata(new LambdaExpMulAlg<>(Lit, Add, Mul), delay); | |
} | |
public static <R> Function<ExpMul, R> cata(ExpMul.ExpMulAlg<R, R> expMulAlg, | |
Function<Supplier<R>, R> delay) { | |
ExpMul.ExpMulAlg<ExpMul, R> lazyExpMulAlg = new CataExpMulAlg<>(expMulAlg, delay); | |
return expMul -> delay.apply(() -> expMul.accept(lazyExpMulAlg)); | |
} | |
public static ExpMul.ExpMulAlg<ExpMul, ExpMul> factory() { | |
return factory; | |
} | |
public interface AddMapper<E, R> { | |
R Add(E e1, E e2); | |
} | |
public interface MulMapper<E, R> { | |
R Mul(E e1, E e2); | |
} | |
private static final class LambdaExpMulAlg<E, R> implements ExpMul.ExpMulAlg<E, R> { | |
private final Function<Integer, R> Lit; | |
private final AddMapper<E, R> Add; | |
private final MulMapper<E, R> Mul; | |
LambdaExpMulAlg(Function<Integer, R> Lit, AddMapper<E, R> Add, MulMapper<E, R> Mul) { | |
this.Lit = Lit; | |
this.Add = Add; | |
this.Mul = Mul; | |
} | |
@Override | |
public R Lit(int lit) { | |
return this.Lit.apply(lit); | |
} | |
@Override | |
public R Add(E e1, E e2) { | |
return this.Add.Add(e1, e2); | |
} | |
@Override | |
public R Mul(E e1, E e2) { | |
return this.Mul.Mul(e1, e2); | |
} | |
} | |
private static final class Lit implements ExpMul { | |
private final int lit; | |
Lit(int lit) { | |
this.lit = lit; | |
} | |
@Override | |
public <R> R accept(ExpMul.ExpMulAlg<ExpMul, R> alg) { | |
return alg.Lit(this.lit); | |
} | |
} | |
private static final class Add implements ExpMul { | |
private final ExpMul e1; | |
private final ExpMul e2; | |
Add(ExpMul e1, ExpMul e2) { | |
this.e1 = e1; | |
this.e2 = e2; | |
} | |
@Override | |
public <R> R accept(ExpMul.ExpMulAlg<ExpMul, R> alg) { | |
return alg.Add(this.e1, this.e2); | |
} | |
} | |
private static final class Mul implements ExpMul { | |
private final ExpMul e1; | |
private final ExpMul e2; | |
Mul(ExpMul e1, ExpMul e2) { | |
this.e1 = e1; | |
this.e2 = e2; | |
} | |
@Override | |
public <R> R accept(ExpMul.ExpMulAlg<ExpMul, R> alg) { | |
return alg.Mul(this.e1, this.e2); | |
} | |
} | |
private static final class Lazy implements ExpMul { | |
private volatile Supplier<ExpMul> expression; | |
private ExpMul evaluation; | |
Lazy(Supplier<ExpMul> expMul) { | |
this.expression = expMul; | |
} | |
private synchronized ExpMul _evaluate() { | |
Lazy lazy = this; | |
while (true) { | |
Supplier<ExpMul> expr = lazy.expression; | |
if (expr == null) { | |
evaluation = lazy.evaluation; | |
break; | |
} | |
else { | |
ExpMul eval = expr.get(); | |
if (eval instanceof Lazy) { | |
lazy = (Lazy) eval; | |
} | |
else { | |
evaluation = eval; | |
break; | |
} | |
} | |
} | |
expression = null; | |
return evaluation; | |
} | |
@Override | |
public <R> R accept(ExpMul.ExpMulAlg<ExpMul, R> alg) { | |
return (this.expression == null ? this.evaluation : _evaluate()).accept(alg); | |
} | |
} | |
public static class CasesMatchers { | |
private static final TotalMatcher_Lit totalMatcher_Lit = new TotalMatcher_Lit(); | |
private CasesMatchers() { | |
} | |
public static final class TotalMatcher_Lit { | |
TotalMatcher_Lit() { | |
} | |
public final <R> TotalMatcher_Add<R> Lit(Function<Integer, R> Lit) { | |
return new TotalMatcher_Add<>(Lit); | |
} | |
public final <R> TotalMatcher_Add<R> Lit_(R r) { | |
return this.Lit((lit) -> r); | |
} | |
public final <R> PartialMatcher_Mul<R> Add(AddMapper<ExpMul, R> Add) { | |
return new PartialMatcher_Mul<>(null, Add); | |
} | |
public final <R> PartialMatcher_Mul<R> Add_(R r) { | |
return this.Add((e1, e2) -> r); | |
} | |
public final <R> PartialMatcher<R> Mul(MulMapper<ExpMul, R> Mul) { | |
return new PartialMatcher<>(null, null, Mul); | |
} | |
public final <R> PartialMatcher<R> Mul_(R r) { | |
return this.Mul((e1, e2) -> r); | |
} | |
} | |
public static final class TotalMatcher_Add<R> extends PartialMatcher_Mul<R> { | |
TotalMatcher_Add(Function<Integer, R> Lit) { | |
super(Lit, null); | |
} | |
public final TotalMatcher_Mul<R> Add(AddMapper<ExpMul, R> Add) { | |
return new TotalMatcher_Mul<>(((PartialMatcher<R>) this).Lit, Add); | |
} | |
public final TotalMatcher_Mul<R> Add_(R r) { | |
return this.Add((e1, e2) -> r); | |
} | |
} | |
public static final class TotalMatcher_Mul<R> extends PartialMatcher<R> { | |
TotalMatcher_Mul(Function<Integer, R> Lit, AddMapper<ExpMul, R> Add) { | |
super(Lit, Add, null); | |
} | |
public final Function<ExpMul, R> Mul(MulMapper<ExpMul, R> Mul) { | |
ExpMul.ExpMulAlg<ExpMul, R> alg = ExpMuls.alg(((PartialMatcher<R>) this).Lit, ((PartialMatcher<R>) this).Add, Mul); | |
return expMul -> expMul.accept(alg); | |
} | |
public final Function<ExpMul, R> Mul_(R r) { | |
return this.Mul((e1, e2) -> r); | |
} | |
} | |
public static class PartialMatcher_Mul<R> extends PartialMatcher<R> { | |
PartialMatcher_Mul(Function<Integer, R> Lit, AddMapper<ExpMul, R> Add) { | |
super(Lit, Add, null); | |
} | |
public final PartialMatcher<R> Mul(MulMapper<ExpMul, R> Mul) { | |
return new PartialMatcher<>(((PartialMatcher<R>) this).Lit, ((PartialMatcher<R>) this).Add, Mul); | |
} | |
public final PartialMatcher<R> Mul_(R r) { | |
return this.Mul((e1, e2) -> r); | |
} | |
} | |
public static class PartialMatcher<R> { | |
private final Function<Integer, R> Lit; | |
private final AddMapper<ExpMul, R> Add; | |
private final MulMapper<ExpMul, R> Mul; | |
PartialMatcher(Function<Integer, R> Lit, AddMapper<ExpMul, R> Add, MulMapper<ExpMul, R> Mul) { | |
this.Lit = Lit; | |
this.Add = Add; | |
this.Mul = Mul; | |
} | |
public final Function<ExpMul, R> otherwise(Supplier<R> otherwise) { | |
ExpMul.ExpMulAlg<ExpMul, R> alg = ExpMuls.<R>alg(this.Lit != null ? this.Lit : (lit) -> otherwise.get(), | |
this.Add != null ? this.Add : (e1, e2) -> otherwise.get(), | |
this.Mul != null ? this.Mul : (e1, e2) -> otherwise.get()); | |
return expMul -> expMul.accept(alg); | |
} | |
public final Function<ExpMul, R> otherwise_(R r) { | |
return this.otherwise(() -> r); | |
} | |
public final Function<ExpMul, Optional<R>> otherwiseEmpty() { | |
ExpMul.ExpMulAlg<ExpMul, Optional<R>> alg = ExpMuls.alg((this.Lit != null) ? (lit) -> Optional.of(this.Lit.apply(lit)) | |
: (lit) -> Optional.empty(), | |
(this.Add != null) ? (e1, e2) -> Optional.of(this.Add.Add(e1, e2)) | |
: (e1, e2) -> Optional.empty(), | |
(this.Mul != null) ? (e1, e2) -> Optional.of(this.Mul.Mul(e1, e2)) | |
: (e1, e2) -> Optional.empty()); | |
return expMul -> expMul.accept(alg); | |
} | |
} | |
} | |
public static class CaseOfMatchers { | |
private CaseOfMatchers() { | |
} | |
public static final class TotalMatcher_Lit { | |
private final ExpMul _expMul; | |
TotalMatcher_Lit(ExpMul _expMul) { | |
this._expMul = _expMul; | |
} | |
public final <R> TotalMatcher_Add<R> Lit(Function<Integer, R> Lit) { | |
return new TotalMatcher_Add<>(this._expMul, Lit); | |
} | |
public final <R> TotalMatcher_Add<R> Lit_(R r) { | |
return this.Lit((lit) -> r); | |
} | |
public final <R> PartialMatcher_Mul<R> Add(AddMapper<ExpMul, R> Add) { | |
return new PartialMatcher_Mul<>(this._expMul, null, Add); | |
} | |
public final <R> PartialMatcher_Mul<R> Add_(R r) { | |
return this.Add((e1, e2) -> r); | |
} | |
public final <R> PartialMatcher<R> Mul(MulMapper<ExpMul, R> Mul) { | |
return new PartialMatcher<>(this._expMul, null, null, Mul); | |
} | |
public final <R> PartialMatcher<R> Mul_(R r) { | |
return this.Mul((e1, e2) -> r); | |
} | |
} | |
public static final class TotalMatcher_Add<R> extends PartialMatcher_Mul<R> { | |
TotalMatcher_Add(ExpMul _expMul, Function<Integer, R> Lit) { | |
super(_expMul, Lit, null); | |
} | |
public final TotalMatcher_Mul<R> Add(AddMapper<ExpMul, R> Add) { | |
return new TotalMatcher_Mul<>(((PartialMatcher<R>) this)._expMul, ((PartialMatcher<R>) this).Lit, Add); | |
} | |
public final TotalMatcher_Mul<R> Add_(R r) { | |
return this.Add((e1, e2) -> r); | |
} | |
} | |
public static final class TotalMatcher_Mul<R> extends PartialMatcher<R> { | |
TotalMatcher_Mul(ExpMul _expMul, Function<Integer, R> Lit, AddMapper<ExpMul, R> Add) { | |
super(_expMul, Lit, Add, null); | |
} | |
public final R Mul(MulMapper<ExpMul, R> Mul) { | |
ExpMul.ExpMulAlg<ExpMul, R> alg = ExpMuls.alg(((PartialMatcher<R>) this).Lit, ((PartialMatcher<R>) this).Add, Mul); | |
return ((PartialMatcher<R>) this)._expMul.accept(alg); | |
} | |
public final R Mul_(R r) { | |
return this.Mul((e1, e2) -> r); | |
} | |
} | |
public static class PartialMatcher_Mul<R> extends PartialMatcher<R> { | |
PartialMatcher_Mul(ExpMul _expMul, Function<Integer, R> Lit, AddMapper<ExpMul, R> Add) { | |
super(_expMul, Lit, Add, null); | |
} | |
public final PartialMatcher<R> Mul(MulMapper<ExpMul, R> Mul) { | |
return new PartialMatcher<>(((PartialMatcher<R>) this)._expMul, ((PartialMatcher<R>) this).Lit, ((PartialMatcher<R>) this).Add, Mul); | |
} | |
public final PartialMatcher<R> Mul_(R r) { | |
return this.Mul((e1, e2) -> r); | |
} | |
} | |
public static class PartialMatcher<R> { | |
private final ExpMul _expMul; | |
private final Function<Integer, R> Lit; | |
private final AddMapper<ExpMul, R> Add; | |
private final MulMapper<ExpMul, R> Mul; | |
PartialMatcher(ExpMul _expMul, Function<Integer, R> Lit, AddMapper<ExpMul, R> Add, | |
MulMapper<ExpMul, R> Mul) { | |
this._expMul = _expMul; | |
this.Lit = Lit; | |
this.Add = Add; | |
this.Mul = Mul; | |
} | |
public final R otherwise(Supplier<R> otherwise) { | |
ExpMul.ExpMulAlg<ExpMul, R> alg = ExpMuls.<R>alg(this.Lit != null ? this.Lit : (lit) -> otherwise.get(), | |
this.Add != null ? this.Add : (e1, e2) -> otherwise.get(), | |
this.Mul != null ? this.Mul : (e1, e2) -> otherwise.get()); | |
return this._expMul.accept(alg); | |
} | |
public final R otherwise_(R r) { | |
return this.otherwise(() -> r); | |
} | |
public final Optional<R> otherwiseEmpty() { | |
ExpMul.ExpMulAlg<ExpMul, Optional<R>> alg = ExpMuls.alg((this.Lit != null) ? (lit) -> Optional.of(this.Lit.apply(lit)) | |
: (lit) -> Optional.empty(), | |
(this.Add != null) ? (e1, e2) -> Optional.of(this.Add.Add(e1, e2)) | |
: (e1, e2) -> Optional.empty(), | |
(this.Mul != null) ? (e1, e2) -> Optional.of(this.Mul.Mul(e1, e2)) | |
: (e1, e2) -> Optional.empty()); | |
return this._expMul.accept(alg); | |
} | |
} | |
} | |
private static final class CataExpMulAlg<R> implements ExpMul.ExpMulAlg<ExpMul, R> { | |
private final ExpMul.ExpMulAlg<R, R> expMulAlg; | |
private final Function<Supplier<R>, R> delay; | |
CataExpMulAlg(ExpMul.ExpMulAlg<R, R> expMulAlg, Function<Supplier<R>, R> delay) { | |
this.expMulAlg = expMulAlg; | |
this.delay = delay; | |
} | |
@Override | |
public R Lit(int lit) { | |
return this.expMulAlg.Lit(lit); | |
} | |
@Override | |
public R Add(ExpMul e1, ExpMul e2) { | |
return this.expMulAlg.Add(this.delay.apply(() -> e1.accept(this)), this.delay.apply(() -> e2.accept(this))); | |
} | |
@Override | |
public R Mul(ExpMul e1, ExpMul e2) { | |
return this.expMulAlg.Mul(this.delay.apply(() -> e1.accept(this)), this.delay.apply(() -> e2.accept(this))); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment