Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 Generic of Generic for Monad Transformer

I'm using "totally lazy" and I have a desire for Either<String,Option<A>> in a program I'm writing. This is a terrific place to use a Monad Transformer for Option (similar to the awesome one that exists in Scalaz 7). I can't seem to get the Generics right in Java 8. The code below is what I would love for it to look like (for a start). Any suggestions of how to get it to work/compile would be AMAZING!!! Please help me get this Monad Transformer to exist for my Java 8 code.

import com.googlecode.totallylazy.Monad;
import com.googlecode.totallylazy.Option;
import com.googlecode.totallylazy.functions.Function1;
import static com.google.common.base.Preconditions.checkNotNull;

public class OptionT<M extends Monad,A> {
   final M<Option<A>> run;

   public OptionT(final M<Option<A>> run){
       this.run = checkNotNull(run);
   }

   public <B> OptionT<M,B> map(Function1<A,B> f){
       return new OptionT<M,B>(run.map(o-> o.map(f)));
   }
}

EDIT: I get the following compiler failure:

OptionT.java:15: error: unexpected type
    final M<A> run;
          ^
  required: class
  found:    type parameter M
  where M is a type-variable:
    M extends Monad<Option<?>> declared in class OptionT
OptionT.java:17: error: unexpected type
    public OptionT(final M<A> run){
                         ^
  required: class
  found:    type parameter M
  where M is a type-variable:
    M extends Monad<Option<?>> declared in class OptionT
like image 887
jordan3 Avatar asked Aug 17 '15 23:08

jordan3


1 Answers

You can do this with the cyclops-monad-api, there is a introductory blog post that you might find helpful here. I am the author of the library and blog post.

I've posted a working implementation of your example (for JDK 8 Optional) below -

public class OptionT<A> {
   @Getter
   final AnyM<Optional<A>> run;

   public OptionT(final AnyM<Optional<A>> run){
       this.run = run;
   }

   public <B> OptionT<B> map(Function<A,B> f){
       return new OptionT<B>(run.map(o-> o.map(f)));
   }


}

@Test
public void test() {
    OptionT<Integer> optionT = new OptionT<>(AnyM.ofMonad(Stream.of(Optional.of(10))));
    System.out.println(optionT.map(num->"hello world"+num).getRun().asSequence().firstValue());
}

Will print out

Optional[hello world10]

AnyM wraps any Monad type. Java doesn't support Higher-Kinded-Types, so you can't put generics on generics. You can wrap the monad type behind a common API however, and that's what AnyM does.

If anyone is interested the cyclops-monad-api now has a growing range of Monad Transformers, inspired by this question - thanks OP!

like image 160
John McClean Avatar answered Nov 16 '22 06:11

John McClean