[JAVA] A monad is a design pattern for "expressing the existence of side effects in a method with a return type".

I wrote this article to explain to Java programmers "what is a monad useful for".

What are side effects in a method?

Or something like this

public int getAge() {
   age += 1; //Stop it!
   return age;
}

Or something like this

public double calculateTax(double price) {
   System.out.println("raw price:" + price); //Eh, do you also display ...?
   return price * 0.08;
}

Or something like this

public boolean isLegalPerson(Person person) {
    if (person.getType().equals(PersonType.UNKNOWN))
        throw new RuntimeException(); //At least make an inspection exception ...
    return person.getType().equals(PersonType.LEGAL);
}

All actions other than the input → output of the method (≒ function) are side effects. Of course, not all side effects are bad. But unexpected side effects are bad! !! !! </ font> (Example like above)

So how do you state that there are side effects in the function?

--Write in the document → The document is not written, it becomes obsolete --Annotate → Forget to add or add it when you don't need it

Then, it would be nice if we could express that the function has side effects by ** return type **. ** → The design pattern for that is "monad" **

If the return type can express the existence of side effects ...

//You can see that the value is rewritten just by looking at the type!
public State<Integer> getAge() {
    ...
}
//You can see that it can be displayed just by looking at the mold!
public IO<Double> calculateTax(double price) {
    ....
}
//Just look at the mold and you'll see that it throws an exception!
public Try<Boolean> isLegalPerson(Person person) {
    ....
}

So how do you realize this mechanism?

Mr. Monad "Use an in-language DSL!"

You can create an in-language DSL to state that there are side effects in the monad pattern. In other words, the monad is a design pattern for creating a mini-language (DSL) that is specialized for the purpose of "showing the existence of side effects with a return type". [^ 1] [^ 1]: If you're scared to talk about Kleisli categories, go somewhere ...

  • However, without using the in-language DSL vocabulary
System.out.println("Do you know monads!");
throw new RuntimeException("Do you know monads!");

If you write it normally, there is no point in using the monad pattern. Therefore, it is necessary to program within that frame using an in-language DSL created with a monad pattern. Note that otherwise you will not be able to "state the existence of side effects".

(Don't touch the Servlet API directly even though you are using Spring MVC, it doesn't make sense to use Spring MVC)

Java implementation of State monads (Java 8 version)

As an example, let's create a ** "in-language DSL that can express the state in a function by a return type" ** using a monad pattern in Java.

package monad;
import java.util.function.Function;

class Pair<A> {
    public final Integer state;
    public final A value;

    Pair(A a, Integer s) {
        this.value = a;
        this.state = s;
    }
}

public class State<A> {

    public Function<Integer, Pair<A>> func;
    public State(Function<Integer, Pair<A>> func) { this.func = func; }

    public static <A> State<A> unit(A a) {
        return new State<>(s -> new Pair<>(a, s));
    }

    public <B> State<B> bind(Function<A, State<B>> nextFunc) {
        return new State<>(s -> {
                Pair<A> pair = func.apply(s);
                return nextFunc.apply(pair.value).func.apply(pair.state);
        });
    }

    public static State<Integer> get() {
        return new State<>(s -> new Pair<>(s, s));
    }

    public static State<Void> put(final Integer s) {
        return new State<>(__ -> new Pair<>(null, s));
    }
}

How to use the Java version of the State monad

import static monad.State.get;
import static monad.State.put;
import static monad.State.unit;

public class MonadicExample {

    //The presence of side effects is expressed in the return type
    public static State<Integer> getAge() {
        //This in-language DSL uses the bind method instead of the assignment operator
        return get().bind(age -> 
               put(age + 1).bind(__ -> 
               get()));
   }

   public static void main(String[] args) {
       //I'm calling getAge twice, so 2 is displayed
       getAge().bind(__ -> 
       getAge().bind(age -> {
       System.out.println(age);
       return unit(null);
       })).func.apply(0);
   }

}

Java monads are a bit (quite?) Hard to see ... Java limits

If you write the same process without using the State monad, it will look like this

public class NonMonadicExample {
    private static int age = 0;
    public static int getAge() {
        age = age + 1; //I don't notice the existence of this side effect! !!
        return age;
    }

    public static void main(String[] args) {
        //I'm calling getAge twice, so 2 is displayed
         getAge();
         System.out.println(getAge());
    }

}

Scala makes it easier to write

In functional languages, there is a dedicated syntax sugar to make it easier to write in-language DSLs made with monadic patterns. With scala, you can write like this with syntax sugar dedicated to monad DSL.

def getAge(): State[Int] = for {
    age <- get()
    _   <- put(age + 1)
    age <- get()
} yield age

(for {
   _   <- getAge()
   age <- getAge()
} yield println(age)).run(0)

If you want to know more about monad patterns other than State monads, read books such as "Scala Functional Design & Programming"! https://www.amazon.co.jp/dp/B00WM54V5Q/

"But ... monads are about functional languages, don't they matter to me ..."

I can't say that ~ Optional types, CompletableFuture types, StreamAPI added from Java8, and Observable of RxJava (library for reactive programming), which is popular recently, are actually implemented by monad pattern. It's hard to write because it doesn't have a dedicated syntax like scala.

Also, there seems to be the following library as a mechanism to make it easier to write monads in Java. https://github.com/soabase/soabase-halva/blob/master/halva/src/main/java/io/soabase/halva/comprehension/README.md http://fits.hatenablog.com/entry/2015/05/16/204101

Recommended Posts