Java泛型:如何用Java编码Functor接口?

Lan*_*dei 17 java generics

我想用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);
}
Run Code Online (Sandbox Code Playgroud)

但是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);
}
Run Code Online (Sandbox Code Playgroud)

[澄清]

对于"适当的子类",我指的是被称为自身的类的类型.例如列表是算子,所以我想写类似的东西

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); 
  }  
}
Run Code Online (Sandbox Code Playgroud)

我知道即使使用我给出的第一个定义也可以写这个(因为允许使用协变返回类型),但是我希望返回类型"ListFunctor" 由类型系统强制执行(这样我就不能返回相反,FooFunctor),这意味着Functor接口需要返回"自我类型"(至少在其他语言中被称为).

[结果]

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

[后果]

我偶然发现了这个古老的问题,并意识到这是我的图书馆highJ的惊人旅程的起点,不仅仅是一个简单的Functor.我永远不会想象人们会把这些疯狂的东西用于任何严肃的事情,但事情发生了,这让我很开心.

Ser*_*nov 5

public interface Functor<A, FInst extends Functor<A,FInst>> {
    public <B, I extends Functor<B,FInst>> I fmap(F<A,B> f);
}
Run Code Online (Sandbox Code Playgroud)

此代码生成错误,因为在定义时I,将其定义为子类Functor<B,FInst>,但Functor<B,FInst>在这种情况下,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);
  }
}
Run Code Online (Sandbox Code Playgroud)

这是有效的,并且它正确地将允许的返回类型集限制为ListFunctor,但它并不仅限于它的子类ListFunctor<B>.您可以将其声明为返回ListFunctor<A>或任何其他ListFunctor,它仍然可以编译.但是您不能将其声明为返回FooFunctor或任何其他Functor.

解决其余问题的主要问题是你不能只将FClass限制为子类ListFunctor<B>,因为B参数是在方法级别声明的,而不是在类级别,所以你不能写

public class ListFunctor<A> implements Functor<A, ListFunctor<B>> {
Run Code Online (Sandbox Code Playgroud)

因为B在那一点上没有任何意义.我无法使用fmap()的第二个参数,但即使我可以,它只会强制您指定两次返回类型 - 一次在type参数中,再一次作为返回类型本身.