5

Is general case of monad expressible in Java 6? Note the words "general case" — it may be possible that general case of monad is not expressible, although many particular cases of monad (i.e. many specific monads) are expressible.

The problem here is (lack of) Higher-kinded generics in Java ; however, I saw that sample Haskell code was really ported to Java using the approach like https://stackoverflow.com/a/877036/1123502 (that is, public class Fix<F extends Fix<F>>).

Of course, non-type-safe implementations (like using Object and downcasts) are not interesting.

Update: there are 2 common monad definitions: join-fmap and bind-return. Although they are (mathematically) equivalent, they may be not equivalent in the sense that one definition is expressible in Java, whereas other is not (however, it seems to me, that non-equivalence is unlikely). So my question concern both definitions.

The bottom line: did anyone overcome all obstacles and wrote "general case" monad in Java 6? Or, alternatively, please point out a paper, or a thorough blog post, or thoroughly explain why it is not possible.

Community
  • 1
  • 1
user1123502
  • 378
  • 3
  • 13
  • 2
    See also [*Monads in Java*](http://logicaltypes.blogspot.com/2011/09/monads-in-java.html). – trashgod Nov 25 '12 at 15:28
  • 2
    @trashgod Note though that in that implementation the return type of `bind` is `Monad` - not `M`, which wouldn't be possible in Java. Consequently if you have a List class that inherits from Monad, there is no guarantee that calling `bind` on such a list will produce another list, so it wouldn't be legal to write something like `MonadicList strings = myMonadicList.bind(...)` without a cast. ... – sepp2k Nov 25 '12 at 16:20
  • 1
    ... So the abstract class given in that article isn't an entirely correct implementation of the monad concept (though it's probably as close to correct as you can get in Java). – sepp2k Nov 25 '12 at 16:20
  • 1
    Also the article says "The unit function, η, comes for free in Java: it's called new.". That would be true if it weren't the fact that it's illegal in Java to write `new M` where `M` is a type parameter. So this makes it impossible to create instances of an arbitrary monadic type in a generic method (without reflection tricks like passing `Class` objects around). – sepp2k Nov 25 '12 at 16:30
  • @sepp2k: Your constructive critique of the article cited would be a useful answer. – trashgod Nov 25 '12 at 21:11
  • Just out of curiosity, why java 6 and not the more recent java 7? Is it trivially known to be possible in java 7 or something? – Tarrasch Nov 26 '12 at 02:01
  • @Tarrasch: The problem here is a limitation of Java's type system, and there haven't been any changes to Java's type system since the introduction of Generics in Java 5, IIRC. There may be a change with the introduction of function types and the possible removal of primitives, but neither of those things are even on the horizon yet. (Removal of primitives is being discussed for "Java 10 or later", function types are just an idea at this point.) – Jörg W Mittag Nov 26 '12 at 03:42

1 Answers1

5

Not without dirty casting tricks. As you already noted Java doesn't support type level polymorphism (a.k.a. "higher kinded types" in Scala land).

Here is one way: Say you want to implement a functor. You would like to write Functor<F<A>>, where F is e.g. a List or Maybe, but that doesn't work. But you can have a "base class" Base<X,Y> for higher-kinded stuff. X must be a "witness" for your real class like List. Y is the usual generic parameter. Now your functor becomes Functor<Base<F,A>>, but all classes that want to be used with this, need to implement Base<X,Y>:

class List<A> implements Base<List.Witness,A> {
   public class Witness{}
   ...
}

public interface Functor<F> {
    public <A, B> Base<F, B> map(F1<A, B> fn, Base<F, A> nestedA);
}

public class ListFunctor implements Functor<List.Witness> {
    public <A, B> Base<List.Witness, B> map(F1<A, B> fn, Base<List.Witness, A> nestedA) {
       ...
    }  
}

Of course the price to pay is that you get back a Base<List.Witness,B>, not a List<B>. This might be fine if you stay in that higher-kinded domain, and of course you can have conversion functions for convenience, but it's still not very nice.

For an implementation see my not-so-serious project highJ. Note that I'm working on a completely rewritten and slightly more convenient version closer to the example above.

For serious code, consider writing such stuff in Scala instead (or use Scalaz).

Landei
  • 54,104
  • 13
  • 100
  • 195