jackb jackb - 6 months ago 12
Java Question

Functors in Java

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 Identity Functor over types 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)?

Answer

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));
    }
}