I wrote this article to explain to Java programmers "what is a monad useful for".
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)
--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" **
//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?
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 ...
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)
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());
}
}
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/
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