Last active
May 15, 2018 15:56
-
-
Save SegFaultAX/553af96cf7e1272039a97cf9e59c88ec to your computer and use it in GitHub Desktop.
Pattern matching via `Coproduct<A, B>` [Java]
This file contains hidden or 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
package com.mkbernard.functional.examples; | |
import java.util.function.Function; | |
public abstract class Coproduct<A, B> { | |
public abstract boolean isLeft(); | |
public abstract boolean isRight(); | |
public abstract Left<A, B> left(); | |
public abstract Right<A, B> right(); | |
public abstract <T> T match(Function<Left<A, B>, T> ifLeft, Function<Right<A, B>, T> ifRight); | |
public static <A, B> Coproduct<A, B> left(A value) { | |
return new Left<>(value); | |
} | |
public static <A, B> Coproduct<A, B> right(B value) { | |
return new Right<>(value); | |
} | |
public static final class Left<A, B> extends Coproduct<A, B> { | |
private final A value; | |
Left(A value) { | |
this.value = value; | |
} | |
public A get() { | |
return value; | |
} | |
@Override | |
public boolean isLeft() { | |
return true; | |
} | |
@Override | |
public boolean isRight() { | |
return false; | |
} | |
@Override | |
public Left<A, B> left() { | |
return this; | |
} | |
@Override | |
public Right<A, B> right() { | |
throw new IllegalStateException("not a right-value: " + value); | |
} | |
@Override | |
public <T> T match(Function<Left<A, B>, T> ifLeft, Function<Right<A, B>, T> ifRight) { | |
return ifLeft.apply(this); | |
} | |
} | |
public static class Right<A, B> extends Coproduct<A, B> { | |
private final B value; | |
Right(B value) { | |
this.value = value; | |
} | |
public B get() { | |
return value; | |
} | |
@Override | |
public boolean isLeft() { | |
return false; | |
} | |
@Override | |
public boolean isRight() { | |
return true; | |
} | |
@Override | |
public Left<A, B> left() { | |
throw new IllegalStateException("not a left-value: " + value); | |
} | |
@Override | |
public Right<A, B> right() { | |
return this; | |
} | |
@Override | |
public <T> T match(Function<Left<A, B>, T> ifLeft, Function<Right<A, B>, T> ifRight) { | |
return ifRight.apply(this); | |
} | |
} | |
public abstract static class Expr { | |
public abstract Coproduct<Val, Coproduct<Add, Mul>> toEither(); | |
public static Expr val(int v) { | |
return new Val(v); | |
} | |
public static Expr add(Expr a, Expr b) { | |
return new Add(a, b); | |
} | |
public static Expr mul(Expr a, Expr b) { | |
return new Mul(a, b); | |
} | |
public static class Val extends Expr { | |
private final int value; | |
public Val(int value) { | |
this.value = value; | |
} | |
public int getValue() { | |
return value; | |
} | |
@Override | |
public Coproduct<Val, Coproduct<Add, Mul>> toEither() { | |
return Coproduct.left(this); | |
} | |
} | |
public static class Add extends Expr { | |
private final Expr a; | |
private final Expr b; | |
public Add(Expr a, Expr b) { | |
this.a = a; | |
this.b = b; | |
} | |
public Expr getA() { | |
return a; | |
} | |
public Expr getB() { | |
return b; | |
} | |
@Override | |
public Coproduct<Val, Coproduct<Add, Mul>> toEither() { | |
return Coproduct.right(Coproduct.left(this)); | |
} | |
} | |
public static class Mul extends Expr { | |
private final Expr a; | |
private final Expr b; | |
public Mul(Expr a, Expr b) { | |
this.a = a; | |
this.b = b; | |
} | |
public Expr getA() { | |
return a; | |
} | |
public Expr getB() { | |
return b; | |
} | |
@Override | |
public Coproduct<Val, Coproduct<Add, Mul>> toEither() { | |
return Coproduct.right(Coproduct.right(this)); | |
} | |
} | |
} | |
public static int eval(Expr e) { | |
Coproduct<Expr.Val, Coproduct<Expr.Add, Expr.Mul>> v = e.toEither(); | |
if (v.isLeft()) { | |
return v.left().get().getValue(); | |
} else { | |
Coproduct<Expr.Add, Expr.Mul> v1 = v.right().get(); | |
if (v1.isLeft()) { | |
Expr.Add add = v1.left().get(); | |
return eval(add.getA()) + eval(add.getB()); | |
} else { | |
Expr.Mul mul = v1.right().get(); | |
return eval(mul.getA()) * eval(mul.getB()); | |
} | |
} | |
} | |
public static void main(String[] args) { | |
Expr e1 = Expr.val(1); | |
Expr e2 = Expr.add(Expr.val(1), Expr.val(2)); | |
Expr e3 = Expr.mul(Expr.val(1), Expr.val(2)); | |
Expr e4 = Expr.mul(Expr.add(Expr.val(2), Expr.val(4)), Expr.val(10)); | |
Expr e5 = Expr.mul(Expr.add(e1, e2), e4); | |
System.out.println(eval(e5)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment