package church.math; import static church.lang.operators.Arithmetic.*; import static church.lang.operators.Relational.*; import static church.lang.operators.Streams.$$encode; @SuppressWarnings("unchecked") public class Fraction<T> { public final T a; public final T b; public Fraction(T a, T b) { this.a = a; this.b = b; } public static <T> Fraction<T> fraction(T a, T b) { return new Fraction<>(a, b); } public static interface $Canonical<T> { public Fraction<T> canonical(T n, T d); } public static <T> $Canonical<T> canonical($$prd<T, T> $L0, $Sign<T> $L1, $Gcd<T> $L2, $$dof<T> $L3) { return (n, d) -> { T g = $L0.$prd($L1.sign(d), $L2.gcd(n, d)); return fraction($L3.$dof(n, g), $L3.$dof(d, g)); }; } public static <T, U> $$encode<T, Fraction<U>> $encode($$equal<U> $L0, $Multiplicative_identity<U> $L1, $$encode<T, U> $L2, $$encode<T, String> $L3) { return (stream, $0) -> $L0.$equal($0.b, $L1.multiplicative_identity()) ? $L2.$encode(stream, $0.a) : $L2.$encode($L3.$encode($L2.$encode(stream, $0.a), "/"), $0.b); } public static <T> $$equal<Fraction<T>> $equal($$equal<T> $L0) { return ($0, $1) -> ($L0.$equal($0.a, $1.a) && $L0.$equal($0.b, $1.b)); } public static <T> $Compare<Fraction<T>> compare($Compare<T> $L0, $$prd<T, T> $L1) { return ($0, $1) -> $L0.compare($L1.$prd($0.a, $1.b), $L1.$prd($1.a, $0.b)); } public static <T> $$sum<Fraction<T>> $sum($Canonical<T> $L0, $$sum<T> $L1, $$prd<T, T> $L2) { return ($0, $1) -> $L0.canonical($L1.$sum($L2.$prd($0.a, $1.b), $L2.$prd($1.a, $0.b)), $L2.$prd($0.b, $1.b)); } public static <T> $$neg<Fraction<T>> $neg($$neg<T> $L0) { return $0 -> fraction($L0.$neg($0.a), $0.b); } public static <T, U> $$prd<Fraction<T>, Fraction<U>> $prd($Canonical<U> $L0, $$prd<T, U> $L1) { return ($0, $1) -> $L0.canonical($L1.$prd($0.a, $1.a), $L1.$prd($0.b, $1.b)); } public static <T> $$rcp<Fraction<T>> $rcp($$lt<T> $L0, $Additive_identity<T> $L1, $$neg<T> $L2) { return $0 -> $L0.$lt($0.a, $L1.additive_identity()) ? fraction($L2.$neg($0.b), $L2.$neg($0.a)) : fraction($0.b, $0.a); } public static <T> $Additive_identity<Fraction<T>> additive_identity($Additive_identity<T> $L0, $Multiplicative_identity<T> $L1) { return () -> fraction($L0.additive_identity(), $L1.multiplicative_identity()); } public static <T> $Multiplicative_identity<Fraction<T>> multiplicative_identity($Multiplicative_identity<T> $L0) { return () -> fraction($L0.multiplicative_identity(), $L0.multiplicative_identity()); } }