Recientemente descubrí cómo simular tipos de orden superior en Java de una manera algo indirecta como esta
interface H<F, T> { } Aquí H codifica un tipo de orden superior que toma un parámetro de tipo F que a su vez toma el parámetro T
Ahora, esto me deja preguntándome, ¿podemos usar esto para implementar algunas construcciones más avanzadas? Por ejemplo, punto fijo de funtores como Fix en Haskell y sus catamorfismos correspondientes.
De hecho, esto se puede hacer traduciendo cuidadosamente las correspondientes contrapartes de Haskell. Aunque esto introduce mucho ruido de línea, la implementación es bastante parecida a la original:
// Encoding of higher kinded type F of T public interface H<F, T> { } public interface Functor<F, T> { <R> H<F, R> map(Function<T, R> f); } // newtype Fix f = Fix {unfix::f (Fix f)} public static record Fix<F extends H<F, T> & Functor<F, T>, T>(F f) { public Functor<F, Fix<F, T>> unfix() { return (Functor<F, Fix<F, T>>) f; } } // type Algebra fa = fa -> a public interface Algebra<F, T> extends Function<H<F, T>, T> {} // cata :: Functor f => Algebra fa -> Fix f -> a // cata alg = alg . fmap (cata alg) . unfix public static <F extends H<F, T> & Functor<F, T>, T> Function<Fix<F, T>, T> cata(Algebra<F, T> alg) { return fix -> alg.apply(fix.unfix().map(cata(alg))); }Sorprendentemente, esto funciona y puede usarse para implementar, por ejemplo, intérpretes para álgebras de expresión.
// evalExprF :: Algebra ExprF Int // evalExprF (Const n) = n // evalExprF (Add mn) = m + n // evalExprF (Mul mn) = m * n public static class ExprAlg implements Algebra<Expr, Integer> { @Override public Integer apply(H<Expr, Integer> hExpr) { return Expr.expr(hExpr).match( conzt -> conzt.n, add -> add.t1 + add.t2, mul -> mul.t1 * mul.t2); } }Ejemplo de trabajo completo en mi repositorio de GitHub .