I'm trying to define classes in Java that are similar to Haskell's functors. Hereby, a functor is defined as:
/**
* Programming languages allow only (just simply enough) endofunctor, that are functors from and to the same category.
* In this case, the category is the one of the datatypes (in here Type, in order to make it more clear)
*/
public interface EndoFunctor<X extends Type> extends Type {
/**
* The basic implementation for any element fx
* @param map Transformation function for the type parameter
* @param fx Element of the current class
* @param <Y> Target type
* @return transformed element through map
*/
<Y extends Type> EndoFunctor<Y> fmap(Function<X,Y> map, EndoFunctor<X> fx);
}
If I want to implement a functor, I have to write something like
public class Id<X extends Type> implements EndoFunctor<X> {
protected X witness;
Id(X witness) { this.witness = witness; }
@Override
public <Y extends Type> Id<Y> fmap(Function<X, Y> map, Id<X> fx) {
return new Id<>(map.apply(fx.witness));
}
}
The problem with this code is that Id<X>
does not match the type EndoFunctor<X>
. How could I determine fmap
in the EndoFunctor
interface such that if any type K<T>
implements EndoFunctor<T>
and a map function T->U
is given, then K<U>
is returned as a value, without any typecasting (that is, since I know that my object is an Id<T>
, then the result of fmap
"has to be" a Id<U>
, and hence I downcast the result of type EndoFunctor<U>
to such type)?
You could use CRTP:
interface EndoFunctor<X extends Type, T extends EndoFunctor<X, T>> extends Type {
<Y extends Type> EndoFunctor<Y, ?> fmap(Function<X,Y> map, T fx);
}
class Id<X extends Type> implements EndoFunctor<X, Id<X>> {
protected X witness;
Id(X witness) { this.witness = witness; }
@Override
public <Y extends Type> Id<Y> fmap(Function<X, Y> map, Id<X> fx) {
return new Id<>(map.apply(fx.witness));
}
}