package fj.data.hlist; import fj.Show; /** * A basic prelude of values lifted into the type system. */ @SuppressWarnings({"ALL"}) public final class HPre { private HPre() { throw new UnsupportedOperationException(); } /** * A type-level Boolean */ public static class HBool { private HBool() { } } /** * Boolean true */ public static class HTrue extends HBool { private HTrue() { } } /** * Boolean false */ public static class HFalse extends HBool { private HFalse() { } } private static final HTrue hTrue = new HTrue(); private static final HFalse hFalse = new HFalse(); /** * Returns a boolean value whose type represents truth. * * @return a boolean value whose type represents truth. */ public static HTrue hTrue() { return hTrue; } /** * Returns a boolean value whose type represents falsehood. * * @return a boolean value whose type represents falsehood. */ public static HFalse hFalse() { return hFalse; } /** * Type-level boolean conjunction. A value of this type represents evidence that AB -> C * * @param <A> A boolean * @param <B> A boolean * @param <C> The logical implication of A and B */ public static final class HAnd<A extends HBool, B extends HBool, C extends HBool> { private final C v; private HAnd(final C v) { this.v = v; } public C v() { return v; } public static HAnd<HFalse, HFalse, HFalse> hAnd(final HFalse a, final HFalse b) { return new HAnd<HFalse, HFalse, HFalse>(hFalse()); } public static HAnd<HTrue, HFalse, HFalse> hAnd(final HTrue a, final HFalse b) { return new HAnd<HTrue, HFalse, HFalse>(hFalse()); } public static HAnd<HFalse, HTrue, HFalse> hAnd(final HFalse a, final HTrue b) { return new HAnd<HFalse, HTrue, HFalse>(hFalse()); } public static HAnd<HTrue, HTrue, HTrue> hAnd(final HTrue a, final HTrue b) { return new HAnd<HTrue, HTrue, HTrue>(hTrue()); } } /** * Type-level boolean disjunction. A value of this type represents evidence that A+B -> C * * @param <A> A boolean * @param <B> A boolean * @param <C> The logical implication of A or B */ public static final class HOr<A extends HBool, B extends HBool, C extends HBool> { private final C v; private HOr(final C v) { this.v = v; } public C v() { return v; } public static HOr<HFalse, HFalse, HFalse> hOr(final HFalse a, final HFalse b) { return new HOr<HFalse, HFalse, HFalse>(hFalse()); } public static HOr<HTrue, HFalse, HTrue> hOr(final HTrue a, final HFalse b) { return new HOr<HTrue, HFalse, HTrue>(hTrue()); } public static HOr<HFalse, HTrue, HTrue> hOr(final HFalse a, final HTrue b) { return new HOr<HFalse, HTrue, HTrue>(hTrue()); } public static HOr<HTrue, HTrue, HTrue> hOr(final HTrue a, final HTrue b) { return new HOr<HTrue, HTrue, HTrue>(hTrue()); } } /** * A type-level conditional. The type of the last parameter is implied by the first three. * * @param <T> A boolean * @param <X> The type of Z if T is true. * @param <Y> The type of Z if T is false. * @param <Z> A type that is either X or Z, depending on T. */ public static final class HCond<T, X, Y, Z> { private HCond(final Z z) { this.z = z; } private final Z z; public Z v() { return z; } public static <X, Y> HCond<HFalse, X, Y, Y> hCond(final HFalse t, final X x, final Y y) { return new HCond<HFalse, X, Y, Y>(y); } public static <X, Y> HCond<HTrue, X, Y, X> hCond(final HTrue t, final X x, final Y y) { return new HCond<HTrue, X, Y, X>(x); } } /** * Type-level natural numbers. */ public abstract static class HNat<A extends HNat<A>> { public abstract Show<A> show(); public abstract Integer toInteger(); public static HZero hZero() { return new HZero(); } public static <N extends HNat<N>> HSucc<N> hSucc(final N n) { return new HSucc<N>(n); } public static <N extends HNat<N>> N hPred(final HSucc<N> n) { return n.pred; } } /** * Type-level zero */ public static final class HZero extends HNat<HZero> { private HZero() { } public Show<HZero> show() { return Show.showS(hZero -> "HZero"); } public Integer toInteger() { return 0; } } /** * A natural number N + 1 * * @param <N> The predecessor of this number. */ public static final class HSucc<N extends HNat<N>> extends HNat<HSucc<N>> { private HSucc(final N n) { pred = n; } private final N pred; public Show<HSucc<N>> show() { return Show.showS(s -> "HSucc (" + s.show().showS(s) + ')'); } public Integer toInteger() { return 1 + pred.toInteger(); } } /** * Type-level equality. Represents evidence for X and Y being equal, or counterevidence against. */ public static final class HEq<X, Y, B extends HBool> { private final B v; private HEq(final B v) { this.v = v; } public B v() { return v; } /** * Zero is equal to itself. * * @param a Zero * @param b Zero * @return Equality for Zero */ public static HEq<HZero, HZero, HTrue> eq(final HZero a, final HZero b) { return new HEq<HZero, HZero, HTrue>(hTrue()); } /** * Zero is not equal to anything other than zero. */ public static <N extends HNat<N>> HEq<HZero, HSucc<N>, HFalse> eq(final HZero a, final HSucc<N> b) { return new HEq<HZero, HSucc<N>, HFalse>(hFalse()); } /** * Zero is not equal to anything other than zero. */ public static <N extends HNat<N>> HEq<HSucc<N>, HZero, HFalse> eq(final HSucc<N> a, final HZero b) { return new HEq<HSucc<N>, HZero, HFalse>(hFalse()); } /** * A number is equal to another if their predecessors are equal. */ public static <N extends HNat<N>, NN extends HNat<NN>, B extends HBool, E extends HEq<N, NN, B>> HEq<HSucc<N>, HSucc<NN>, B> eq(final HSucc<N> a, final HSucc<NN> b, final E e) { return new HEq<HSucc<N>, HSucc<NN>, B>(e.v()); } } /** * Type-level integer arithmetic */ public static final class HAdd<A extends HNat<A>, B extends HNat<B>, C extends HNat<C>> { private final C sum; private HAdd(final C sum) { this.sum = sum; } public C sum() { return this.sum; } /** * The sum of zero and any other number is that number. */ public static <N extends HNat<N>> HAdd<HZero, HSucc<N>, HSucc<N>> add(final HZero a, final HSucc<N> b) { return new HAdd<HZero, HSucc<N>, HSucc<N>>(b); } /** * The sum of zero and any other number is that number. */ public static <N extends HNat<N>> HAdd<HSucc<N>, HZero, HSucc<N>> add(final HSucc<N> a, final HZero b) { return new HAdd<HSucc<N>, HZero, HSucc<N>>(a); } /** * The sum of numbers a and b is one greater than the sum of b and the predecessor of a. */ public static <N extends HNat<N>, M extends HNat<M>, R extends HNat<R>, H extends HAdd<N, HSucc<M>, R>> HAdd<HSucc<N>, HSucc<M>, HSucc<R>> add(final HSucc<N> a, final HSucc<M> b, final H h) { return new HAdd<HSucc<N>, HSucc<M>, HSucc<R>>(HNat.hSucc(h.sum())); } } }