HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Java monad implementation

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
implementationjavamonad

Problem

I'm learning functional programming and their concept of Monads. I've found nothing more effective in learning than writing an implementation in a programming language I have experience with.

I came up with the following implementation in Java. Could someone please suggest improvements?

So, I have an interface, Bindable:

public interface Bindable {

     Bindable bind(Function> function);

}


And I have the Maybe implementation:

```
public class Maybe implements Bindable {
private final State state;

public static Maybe just(T value) {
return new Maybe(new Just(value));
}

public static Maybe nothing() {
return new Maybe((State) Nothing.INSTANCE);
}

private Maybe(State state) {
this.state = state;
}

@Override
public Bindable bind(final Function> function) {
return state.accept(new StateVisitor>() {
@Override
public Bindable visitJust(T value) {
return function.apply(value);
}

@Override
public Bindable visitNothing() {
return nothing();
}
});
}

@Override
public String toString() {
return Objects.toStringHelper(this)
.add("state", state)
.toString();

}

private static interface State {

E accept(StateVisitor visitor);

}

private static interface StateVisitor {
E visitJust(T value);

E visitNothing();
}

private static class Just implements State {
private final T value;

private Just(T value) {
this.value = value;
}

@Override
public E accept(StateVisitor visitor) {
return visitor.visitJust(value);
}

@Override
public String toString() {
return Objects.toStringHelper(this)
.add("value", value)
.toString();
}
}

pr

Solution

As mentioned in the comments, the problem with implementing monads in Java is that in an OO language class methods always work on a single instance. Type classes in Haskell are very different, there you can create values "out of nowhere" like in

class Monad m where
    return :: a -> m a
    -- ...


or

class Monoid a where
    mempty :: a
    -- ...


There is a functional library for Scala called Scalaz, which solves the problem in the following way: Instead of having an object implement an interface such as Bindable, it creates a separate object that carries all the functions of a "type class". Unfortunately this requires generic type parameters that take parameters themselves, so called higher-order kinds, which Java doesn't support. If Java had them, we'd write something like

public interface Monad> {
public M pure(A value); // return is a keyword
public M bind(M v, Function> f);
}


and then for each monad type you'd define a singleton that implements this interface, such as Monad. However, Java doesn't allow this. And another problem is that you have to pass this singleton around in every computation, which is very inconvenient.

If you want to explore such functional concepts in a Java-like language, probably the best bet is to start learning Scala. Scala has implicit parameters which solve the problem with passing singletons around, and also has higher-order type parameters. In Scala you'd do something like

trait Monad[M[_]] {
def pureA: M[A];
def bindA,B: M[B];
}

implicit object OptionMonad extends Monad[Option] {
override def pureA: Option[A]
= Some(value);
// in most cases Scala's flatMap corresponds to bind
override def bindA,B: Option[B]
= v.flatMap(f);
}

// Generic monadic computations use implicit parameters:
def liftM2[M[_],A,B,C](f: (A,B) => C, x: M[A], y: M[B])
(implicit m: Monad[M]): M[C] =
m.bind(x, (x1: A) => m.bind(y, (y1: B) => m.pure(f(x1, y1))))

def sequence[M[_],A](xs: List[M[A]])(implicit m: Monad[M]): M[List[A]] =
xs match {
case Nil => m.pure(Nil)
case x :: xs => liftM2[M,A,List[A],List[A]](_ :: _, x, sequence(xs))
}

System.out.println(sequence(List[Option[Int]](Some(1), Some(2))))
System.out.println(sequence(List[Option[Int]](Some(1), None)))


Note that Scala has it's own concept for dealing with monadic computations using for-comprehensions, but that's out of the scope of this question.

Code Snippets

class Monad m where
    return :: a -> m a
    -- ...
class Monoid a where
    mempty :: a
    -- ...

Context

StackExchange Code Review Q#8055, answer score: 8

Revisions (0)

No revisions yet.