patternjavaMinor
Java monad implementation
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,
And I have the
```
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
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
or
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
and then for each monad type you'd define a singleton that implements this interface, such as
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
Note that Scala has it's own concept for dealing with monadic computations using
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 likepublic 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.