Java中的函数

时间:2016-06-04 13:35:44

标签: java haskell category-theory

我正在尝试在Java中定义类似于Haskell函子的类。因此,仿函数定义为:

/**
 * Programming languages allow only (just simply enough) endofunctor, that are functors from and to the same category.
 * In this case, the category is the one of the datatypes (in here Type, in order to make it more clear)
 */
public interface EndoFunctor<X extends Type> extends Type {

    /**
     * The basic implementation for any element fx
     * @param map   Transformation function for the type parameter
     * @param fx    Element of the current class
     * @param <Y>   Target type
     * @return      transformed element through map
     */
    <Y extends Type> EndoFunctor<Y> fmap(Function<X,Y> map, EndoFunctor<X> fx);

}

如果我想实现一个Identity Functor over types仿函数,我必须写一些类似

的东西
public class Id<X extends Type> implements EndoFunctor<X> {
    protected X witness;
    Id(X witness) { this.witness = witness; }
    @Override
    public <Y extends Type> Id<Y> fmap(Function<X, Y> map, Id<X> fx) {
        return new Id<>(map.apply(fx.witness));
    }
}

此代码存在的问题是Id<X>EndoFunctor<X>类型不匹配。如何在fmap界面中确定EndoFunctor,以便K<T>实施EndoFunctor<T>任何类型T->U并给出地图函数K<U>,然后{{1}返回为一个值,没有任何类型转换(也就是说,因为我知道我的对象是Id<T>,那么fmap的结果必须是“Id<U>,并且因此我将类型EndoFunctor<U>的结果向下传播到这种类型)?

3 个答案:

答案 0 :(得分:8)

您可以使用CRTP

interface EndoFunctor<X extends Type, T extends EndoFunctor<X, T>> extends Type {
    <Y extends Type> EndoFunctor<Y, ?> fmap(Function<X,Y> map, T fx);    
}

class Id<X extends Type> implements EndoFunctor<X, Id<X>> {
    protected X witness;
    Id(X witness) { this.witness = witness; }

    @Override
    public <Y extends Type> Id<Y> fmap(Function<X, Y> map, Id<X> fx) {
        return new Id<>(map.apply(fx.witness));
    }
}

答案 1 :(得分:8)

  

如何在EndoFunctor界面中确定fmap,以便如果任何类型K实现EndoFunctor并且给出了地图函数T-> U,那么K将作为值返回,而不进行任何类型转换(也就是说,因为我知道我的对象是一个Id,那么fmap&#34;的结果必须是&#34;一个Id,因此我将EndoFunctor类型的结果向下转换为这样的类型)?

你不能;这被称为高级多态,而Java并不支持它(很少有语言可以支持)。 Jorn Vernee的回答让你尽可能地接近Java,但是那个界面允许你写

class NotId<X extends Type> implements EndoFunctor<X, Id<X>> {

    @Override
    public <Y extends Type> ADifferentEndoFunctorAgain<Y> fmap(Function<X, Y> map, Id<X> fx) { ... }
}
如果您想在EndoFunctor s上编写通用代码,而不是使用{em>特定 EndoFunctor Id,那么

就无法工作。

答案 2 :(得分:2)

问题不是Id<X>EndoFunctor<X>不匹配,而是当您尝试覆盖fmap时,您已使参数类型更具体,因此方法签名没有更长时间与fmap

EndoFunctor的方法签名相匹配

这意味着其当前表单中的Id<X>未完全实现EndoFunctor<X>接口。在实现界面时,必须能够与您的班级进行互动,而无需知道它是一个不同的界面。

请遵循有关删除此方法参数和使用实例变量的注释中的建议,或将Id<X>中的签名修改为public <Y extends Type> Id<Y> fmap(Function<X, Y> map, EndoFunctor<X> fx)以使其与界面兼容。