Functors in Java

I am trying to define Java classes that are similar to Haskell functors. Thus, 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 Identification functor by type 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 the Id<X> does not match the EndoFunctor<X> . How can I define fmap in the EndoFunctor interface so that if some type K<T> implements EndoFunctor<T> , and the mapping function T->U , then K<U> returned as a value without any type casting ( what is it, since I know that my object is Id<T> , then the result of fmap "should be" a Id<U> , and therefore, I omit the result of type EndoFunctor<U> to this type)?

+5
source share
3 answers

You can 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)); } } 
+7
source

How can I define fmap in the EndoFunctor interface in such a way that if any type K implements EndoFunctor and the mapping function T-> U, then K is returned as a value without any type casting (that is, since I know that my the object is Id, then the result of fmap "should be" Id, and therefore I lower the result of type EndoFunctor to that type)?

You can not; this is called a higher polymorphism, and Java does not support it (very few languages). Jorn Vernee's answer gives you the closest you can to Java, but this interface allows you to write

 class NotId<X extends Type> implements EndoFunctor<X, Id<X>> { @Override public <Y extends Type> ADifferentEndoFunctorAgain<Y> fmap(Function<X, Y> map, Id<X> fx) { ... } } 

and it won’t work if you want to write generic code over EndoFunctor instead of working with a specific EndoFunctor , like Id .

+8
source

The problem is not that Id<X> does not match EndoFunctor<X> , but when you tried to override fmap you made the parameter types more specific, and therefore the method signature no longer matches the signature of the fmap method in EndoFunctor

This means that the Id<X> in it the current form does not fully implement the EndoFunctor<X> interface. When implementing an interface, you must be able to interact with your class without knowing that it is a different interface.

Either follow the recommendations in the comments about deleting this method parameter and using an instance variable, or change the signature in Id<X> to public <Y extends Type> Id<Y> fmap(Function<X, Y> map, EndoFunctor<X> fx) to make it compatible with the interface.

+2
source

All Articles