Java Generics Inferred Types

generics, java

Solution

(I'm +1'ing jacobm's answer, I just wanted to elaborate a bit on the underlying problem.)

The problem is that in Java, there is no particular relationship between `GenericClass<S>` and `GenericClass<T>`: I mean, both are subtypes of `GenericType<?>`, but there's no way that `GenericInterface<T>` can refer to the type you'd get by taking `getClass()` and substituting `T` for `S`.

In Haskell, the definition of the `Monad` typeclass looks like this:

class Monad m where
    (>>=)  :: m a -> (a -> m b) -> m b
    return :: a -> m a

Note that it defines `m` by using both `m a` and `m b`, meaning "the same parameterized type `m`, with (potentially) different type-arguments `a` and `b`". In Java you can't create a supertype of `m` (that is, an interface for `m`) that expresses this sort of thing, because while the supertype can refer to itself with arbitrary type-parameters (because it can refer to itself by name, just like how it could use any other generic type), and can refer to an arbitrary subtype with any single type-argument (namely its own), it has no way to refer to an arbitrary subtype with an arbitrary type-parameter. It doesn't sit "outside" the type system in the way that a Haskell typeclass definition does.

This means that there's no real way to define a generic `Monad` interface whose implementations are generic monadic types.

Problem

Ok, so I am implementing the state monad in java. However, I can't seem to get the generics to work right. I have the code below, and am trying to avoid the cases indicated. ``` public interface Monad<M, A> { <B, R extends Monad<M, B>> R bind(Function<? super A, R> p_function); } public class State<S, A> implements Monad<State<S, ?>, A> { private Function<S, Pair<S, A>> m_function; public State(Function<S, Pair<S, A>> p_function) { m_function = p_function; } public final Pair<S, A> run(S p_state) { return m_function.apply(p_state); } @Override public <B, R extends Monad<State<S, ?>, B>> R bind( final Function<? super A, R> p_function) { // I want to avoid the cast to R here return (R) new State<S, B>((S state) -> { Pair<S, A> run = run(state); // And this cast, but they seem related State<S, B> applied = (State<S, B>) p_function.apply(run.second()); return applied.run(run.first()); }); } } ``` Note: I am aware that if I cange the signature of `bind` to `<B> Monad<M, B> bind(Function<? super A, ? extends Monad<M, B>> p_function);` The cast can be avoided. However, this causes a compile error in the following method ``` public static <A, B, C, M, MB extends Monad<M, B>, MC extends Monad<M, C>> Function<A, MC> compose( Function<? super A, MB> p_first, Function<? super B, MC> p_second) { // have to use an anonymous class here, because using a closure causes a // runtime error with the beta version of JDK 8 return new Function<A, MC>() { @Override public MC apply(A arg) { MB monadOfB = p_first.apply(arg); return monadOfB.<C> bind(p_second); // <-- type error here } }; } ``` Now, I also tried changing the signature of `compose` in a similar manner. i.e. rather than `MB extends Monad<M, B>` I used `Monad<M, B>` where MB was used and similarly for MC. This makes the `compose` method compile. However, then the return type could not be correctly inferred by the callers of `compose` i.e. ``` Function<String, State<Integer, String>> left = ...; Function<String, State<Integer, String>> right = ...; Function<String, State<Integer, String>> composed = Monad.compose(left, right); ``` Doesn't work without specifying the types on the method call, whereas before it did. How do I make all these generics play nicely together?

Original source