Я хочу определить класс Functor в Java. Это работает:
//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 должен возвращать "self-type" (по крайней мере, так называется на других языках).
[Результат]
Так что, кажется, то, что я хочу, невозможно. Вот соответствующее сообщение в блоге: http://blog.tmorris.net/higher-order-polymorphism-for-pseudo-java/
[Последствие]
Я наткнулся на этот свой давний вопрос и понял, что это было отправной точкой удивительного путешествия с моей библиотекой highJ, содержащей гораздо больше, чем простой Functor
. Я бы никогда не подумал, что люди будут использовать этот сумасшедший материал для чего-то серьезного, но это случилось, и это меня очень радует.