DerivativeTest.java
package com.acme.symbolic;

import church.lang.ByteStream;
import church.lang.operators.Relational.$$equal;
import church.lang.operators.Streams.$$encode;
import church.primitives.Objects;
import church.util.HashMap;

import static church.lang.Collections.$Empty_set;
import static church.lang.Error.error;
import static church.lang.operators.Streams.output;
import static church.util.HashMap.get;
import static com.acme.symbolic.Derivative.$Derivative;
import static com.acme.symbolic.Expression.*;

@SuppressWarnings("unchecked")
public class DerivativeTest {
    private static final $$equal<String>              $S0 = Objects::$equal;
    private static final $$encode<ByteStream, String> $S1 = Objects::$encode;

    private static interface $I0<T> {
        public T varNameToValue(String name);
    }

    public static interface $Test<T> {
        public ByteStream test(church.lang.Functions.Function1<String, church.lang.Functions.Function1<T, T>> funNameToFunction, church.lang.Functions.Function1<String, church.lang.Functions.Function1<Expression<T>, Expression<T>>> funNameToDerivative, church.lang.Functions.Function1<Expression<T>, Expression<T>> fn, T x0, T expectedFp0);
    }

    public static <T> $Test<T> test($$encode<ByteStream, Expression<T>> $L0, $Evaluate<T> $L1, $$encode<ByteStream, T> $L2, $Derivative<T> $L3, $$equal<T> $L4) {
        return (funNameToFunction, funNameToDerivative, fn, x0, expectedFp0) -> {
            String varName = "x";
            $I0<T> varNameToValue = new $I0<T>() {
                public T varNameToValue(String name) {
                    return $S0.$equal(name, varName) ? x0 : error("Undefined variable");
                }
            };
            Expression<T> x = var(varName);
            Expression<T> f = fn.of(x);
            $S1.$encode($L0.$encode($S1.$encode(output, "f(x)  = "), f), "\n");
            T f0 = $L1.evaluate(funNameToFunction, f, varNameToValue::varNameToValue);
            $S1.$encode($L2.$encode($S1.$encode(output, "f(1)  = "), f0), "\n");
            Expression<T> fp = $L3.derivative(funNameToDerivative, f, x);
            $S1.$encode($L0.$encode($S1.$encode(output, "f'(x) = "), fp), "\n");
            T fp0 = $L1.evaluate(funNameToFunction, fp, varNameToValue::varNameToValue);
            $S1.$encode($L2.$encode($S1.$encode(output, "f'(1) = "), fp0), "\n");
            assert $L4.$equal(expectedFp0, fp0);
            return $S1.$encode(output, "\n");
        };
    }

    public static interface $Test0<T> {
        public ByteStream test0(church.lang.Functions.Function1<Expression<T>, Expression<T>> fn, T x0, T fp0);
    }

    public static <T> $Test0<T> test0($Test<T> $L0, $Empty_set<HashMap<String, church.lang.Functions.Function1<T, T>>> $L1, $Empty_set<HashMap<String, church.lang.Functions.Function1<Expression<T>, Expression<T>>>> $L2) {
        return (fn, x0, fp0) -> $L0.test(name -> get($L1.empty_set(), name), name -> get($L2.empty_set(), name), fn, x0, fp0);
    }

}