我想用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参数中指定一次,在返回类型本身中再指定一次。