我想用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不在其范围内”):
Functor
A
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接口需要返回“自我类型”(至少在其他语言中如此)。
[结果]
所以看来我想要的是不可能的。这是一个相关的博客文章:http : //blog.tmorris.net/higher-order- polymorphism-for-pseudo-java/
[后果]
我偶然发现了我这个古老的问题,意识到这是我的图书馆highJ令人惊叹的旅程的起点,该图书馆包含的内容远不止一个简单的Functor。我永远也不会想象人们会用这种疯狂的东西来处理任何严重的事情,但是事情发生了,这让我感到非常高兴。
这段代码会产生错误,因为您在定义时I将其定义为的子类Functor<B,FInst>,但Functor<B,FInst>在这种情况下FInst参数必须是的子类,而在上面将其定义为的子类Functor<A,FInst>。由于Functor<A,FInst>和Functor<B,FInst>不兼容,因此会出现此错误。
I
Functor<B,FInst>
Functor<A,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>仅子类。您可以将其声明为returning ListFunctor<A>或任何其他ListFunctor,并且仍然可以编译。但是您不能将其声明为返回FooFunctor或任何其他Functor。
ListFunctor<B>
ListFunctor<A>
解决其余问题的主要问题是,您不能将FClass限制为的子类ListFunctor<B>,因为B参数是在方法级别而不是在类级别声明的,因此您不能编写
public class ListFunctor<A> implements Functor<A, ListFunctor<B>> {
因为那时B并不意味着任何东西。我也无法使它与fmap()的第二个参数一起使用,但是即使可以,它也会强制您两次指定返回类型- 在type参数中指定一次,在返回类型本身中再指定一次。