我想用Java定义Functor类。这有效:

//a Function
public interface F<A,R> {
   public R apply(A a);
}

public interface Functor<A> {
   public <B> Functor<B> fmap(F<A,B> f);
}

但是,fmap的返回值应该不是Functor,而是适当的子类。通常,可以使用CRTP对此进行编码,但是由于附加参数A,在这里我似乎遇到了麻烦。例如。以下和类似的编码不起作用(“类型参数FInst不在其范围内”):
public interface Functor<A, FInst extends Functor<A,FInst>> {
    public <B, I extends Functor<B,FInst>> I fmap(F<A,B> f);
}

[说明]

对于“适当的子类”,我指的是被称为自身的类的类型。例如。列表是函子,所以我想写点东西
public class ListFunctor<A> implements ??? {
  final private List<A> list;
  public ListFunctor(List<A> list) {
     this.list = list;
  }

  @Override
  <B> ListFunctor<B> fmap(F<A,B> f) {
     List<B> result = new ArrayList<B>();
     for(A a: list) result.add(f.apply(a));
     return new ListFunctor<B>(result);
  }
}

我知道即使使用我给出的第一个定义,我也可以编写此代码(因为允许使用协变量返回类型),但是我希望返回类型“ListFunctor”由通过类型系统强制执行(因此我不能返回FooFunctor),这意味着Functor接口(interface)需要返回“自我类型”(至少在其他语言中如此)。

[结果]

所以看来我想要的是不可能的。这是一个相关的博客文章:http://blog.tmorris.net/higher-order-polymorphism-for-pseudo-java/

[后果]

我偶然发现了我这个古老的问题,意识到这是我的图书馆highJ令人惊叹之旅的起点,该图书馆包含的内容远不止一个简单的Functor。我永远也不会想象人们会用这种疯狂的东西来处理任何严重的事情,但是事情发生了,这让我感到非常高兴。

最佳答案

public interface Functor<A, FInst extends Functor<A,FInst>> {
    public <B, I extends Functor<B,FInst>> I fmap(F<A,B> f);
}

此代码会产生错误,因为在定义I时,您将其定义为Functor<B,FInst>的子类,但是在这种情况下,FInst参数必须是Functor<B,FInst>的子类,而在上面将其定义为Functor<A,FInst>的子类。由于Functor<A,FInst>Functor<B,FInst>不兼容,因此会出现此错误。

我无法完全解决此问题,但我至少可以完成一半的工作:
import java.util.ArrayList;
import java.util.List;

interface F<A,R> {
   public R apply(A a);
}

interface Functor<A, FClass extends Functor<?, FClass>> {
   public <B> FClass fmap(F<A,B> f);
}

public class ListFunctor<A> implements Functor<A, ListFunctor<?>> {
  final private List<A> list;
  public ListFunctor(List<A> list) {
     this.list = list;
  }

  @Override
  public <B> ListFunctor<B> fmap(F<A,B> f) {
     List<B> result = new ArrayList<B>();
     for(A a: list) result.add(f.apply(a));
     return new ListFunctor<B>(result);
  }
}

这行得通,并且将允许的返回类型的集合适当地限制为ListFunctor,但它并不仅仅将其限制为ListFunctor<B>的子类。您可以将其声明为返回ListFunctor<A>或任何其他ListFunctor,并且仍然可以编译。但是您不能将其声明为返回FooFunctor或任何其他Functor。

解决其余问题的主要问题是,您不能将FClass仅限于ListFunctor<B>的子类,因为B参数是在方法级别而不是在类级别声明的,因此您不能编写
public class ListFunctor<A> implements Functor<A, ListFunctor<B>> {

因为那时B没什么意思。我也无法使它与fmap()的第二个参数一起使用,但是即使可以,它也会强制您两次指定返回类型-在type参数中指定一次,在返回类型本身中再指定一次。

10-05 23:53