Arithmetic.java
package church.lang.operators;

import church.lang.operators.Streams.$$encode;
import church.primitives.Objects;

import static church.lang.Error.error;
import static church.lang.operators.Relational.*;
import static church.lang.operators.Streams.output;

@SuppressWarnings("unchecked")
public class Arithmetic {
    private static final $$encode<church.lang.ByteStream, String> $S0 = Objects::$encode;

    public static interface $Min_value<T> {
        public T min_value();
    }

    public static interface $Max_value<T> {
        public T max_value();
    }

    public static interface $Additive_identity<T> {
        public T additive_identity();
    }

    public static interface $$sum<T> {
        public T $sum(T a, T b);
    }

    public static interface $$neg<T> {
        public T $neg(T a);
    }

    public static interface $$sub<T> {
        public T $sub(T a, T b);
    }

    public static <T> $$sub<T> $sub($$sum<T> $L0, $$neg<T> $L1) {
        return (a, b) -> $L0.$sum(a, $L1.$neg(b));
    }

    public static interface $Sign<T> {
        public T sign(T a);
    }

    public static interface $Multiplicative_identity<T> {
        public T multiplicative_identity();
    }

    public static interface $$prd<S, T> {
        public T $prd(S a, T b);
    }

    public static interface $$pow<T, U> {
        public T $pow(T a, U b);
    }

    public static interface $$rcp<T> {
        public T $rcp(T a);
    }

    public static interface $$div<T, U> {
        public U $div(T a, U b);
    }

    public static <T, U> $$div<T, U> $div($$prd<T, U> $L0, $$rcp<U> $L1) {
        return (a, b) -> $L0.$prd(a, $L1.$rcp(b));
    }

    public static interface $Divide<T, U> {
        public U divide(T a, T b, church.lang.Functions.Function1<T, church.lang.Functions.Function1<T, U>> c);
    }

    public static interface $Quotient<T> {
        public T quotient(T n, T d);
    }

    public static <T> $Quotient<T> quotient($Divide<T, T> $L0) {
        return (n, d) -> $L0.divide(n, d, q -> r -> q);
    }

    public static interface $$rem<T> {
        public T $rem(T n, T d);
    }

    public static <T> $$rem<T> $rem($Divide<T, T> $L0) {
        return (n, d) -> $L0.divide(n, d, q -> r -> r);
    }

    public static interface $$dof<T> {
        public T $dof(T n, T d);
    }

    public static <T> $$dof<T> $dof($Divide<T, T> $L0, $$neq<T> $L1, $Additive_identity<T> $L2) {
        return (n, d) -> $L0.divide(n, d, q -> r -> $L1.$neq(r, $L2.additive_identity()) ? error("Division failed unexpectedly. ") : q);
    }

    public static interface $Gcd<T> {
        public T gcd(T a, T b);
    }

    public static <T> $Gcd<T> gcd($$encode<church.lang.ByteStream, T> $L0, $$equal<T> $L1, $Additive_identity<T> $L2, $$rem<T> $L3) {
        return new $Gcd<T>() {
            public T gcd(T a, T b) {
                $S0.$encode($L0.$encode($S0.$encode($L0.$encode($S0.$encode(output, "gcd> a: "), a), ", b: "), b), "\n");
                return $L1.$equal(b, $L2.additive_identity()) ? a : gcd(b, $L3.$rem(a, b));
            }
        };
    }

}