如何在Java中实现functors的固定点

12

最近我发现了一种在Java中以某种迂回的方式来模拟高阶类型的方法,具体实现可以参考highj

interface H<F, T> { }

在这里,H编码一个更高阶的类型,它接受一个类型参数F,而F本身需要一个参数T
现在我想知道,我们能否使用这个实现一些更高级别的构造?例如,Haskell中的Fix和其相应的catamorphisms
1个回答

10

事实上,可以通过仔细翻译相应的Haskell对应项来实现这一点。虽然这会引入大量行噪声,但实现与原始代码非常接近:

// 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 f a = f a -> a
public interface Algebra<F, T> extends Function<H<F, T>, T> {}

 // cata :: Functor f => Algebra f a -> 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)));
}

令人惊讶的是,这很有效,并可用于实现例如表达式代数解释器

// evalExprF :: Algebra ExprF Int
// evalExprF (Const n) = n
// evalExprF (Add m n) = m + n
// evalExprF (Mul m n) = 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);
    }
}

在我的GitHub存储库中有一个完整的工作示例。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接