[JAVA] Monade ist ein Entwurfsmuster, um "das Vorhandensein von Nebenwirkungen in einer Methode mit einem Rückgabetyp auszudrücken".

Ich habe diesen Artikel geschrieben, um Java-Programmierern zu erklären, "wofür ist Monad nützlich?"

Was sind die Nebenwirkungen der Methode?

Oder so ähnlich

public int getAge() {
   age += 1; //Hör auf!
   return age;
}

Oder so ähnlich

public double calculateTax(double price) {
   System.out.println("raw price:" + price); //Eh, zeigen Sie auch ...?
   return price * 0.08;
}

Oder so ähnlich

public boolean isLegalPerson(Person person) {
    if (person.getType().equals(PersonType.UNKNOWN))
        throw new RuntimeException(); //Zumindest eine Inspektionsausnahme machen ...
    return person.getType().equals(PersonType.LEGAL);
}

Alle Aktionen außer der Eingabe → Ausgabe der Methode (Funktion ≒) sind Nebenwirkungen. Natürlich sind nicht alle Nebenwirkungen schlecht. Aber unerwartete Nebenwirkungen sind schlimm! !! !! </ font> (Beispiel wie oben)

Wie stellen Sie fest, dass die Funktion Nebenwirkungen hat?

  • In das Dokument schreiben → Das Dokument ist nicht geschrieben, es ist veraltet --Annotieren → Vergessen Sie, es hinzuzufügen oder hinzuzufügen, wenn Sie es nicht benötigen

Dann wäre es schön, wenn wir ausdrücken könnten, dass die Funktion Nebenwirkungen durch ** Rückgabetyp ** hat. ** → Das Entwurfsmuster dafür ist "Monade" **

Wenn der Rückgabetyp das Vorhandensein von Nebenwirkungen ausdrücken kann ...

//Sie können sehen, dass der Wert neu geschrieben wird, indem Sie sich nur den Typ ansehen!
public State<Integer> getAge() {
    ...
}
//Sie können sehen, dass es angezeigt werden kann, indem Sie nur auf die Form schauen!
public IO<Double> calculateTax(double price) {
    ....
}
//Sie können sehen, dass Sie eine Ausnahme auslösen können, indem Sie sich nur den Typ ansehen!
public Try<Boolean> isLegalPerson(Person person) {
    ....
}

Wie realisieren Sie diesen Mechanismus?

Mr. Monad "Verwenden Sie DSL in der Sprache!"

Sie können ein DSL in der Sprache erstellen, um anzuzeigen, dass das Monadenmuster Nebenwirkungen aufweist. Mit anderen Worten, Monad ist ein Entwurfsmuster zum Erstellen einer Minisprache (DSL), die darauf spezialisiert ist, "das Vorhandensein von Nebenwirkungen mit einem Rückgabetyp anzuzeigen". [^ 1] [^ 1]: Wenn Sie Angst haben, über das Kreisuri-Gebiet zu sprechen, gehen Sie bitte irgendwohin ...

  • Ohne Verwendung des DSL-Vokabulars in der Sprache
System.out.println("Kennst du Monad!");
throw new RuntimeException("Kennst du Monad!");

Wenn Sie es normal schreiben, macht es keinen Sinn, das Monadenmuster zu verwenden. Daher ist es erforderlich, innerhalb dieses Frames mit einem in der Sprache erstellten DSL zu programmieren, das mit dem Monadenmuster erstellt wurde. Beachten Sie, dass Sie sonst nicht in der Lage sind, "das Vorhandensein von Nebenwirkungen anzugeben".

(Berühren Sie die Servlet-API nicht direkt, obwohl Sie Spring MVC verwenden. Es ist nicht sinnvoll, Spring MVC zu verwenden.)

Java-Implementierung von State Monad (Java 8-Version)

Als Beispiel erstellen wir ein ** "DSL in der Sprache, das den Status in einer Funktion mit einem Rückgabetyp" ** unter Verwendung eines Monadenmusters in Java ausdrücken kann.

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));
    }
}

Verwendung von State Monad für Java

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

public class MonadicExample {

    //Das Vorhandensein von Nebenwirkungen wird im Rückgabetyp ausgedrückt
    public static State<Integer> getAge() {
        //Dieses DSL in der Sprache verwendet die Bindemethode anstelle des Zuweisungsoperators
        return get().bind(age -> 
               put(age + 1).bind(__ -> 
               get()));
   }

   public static void main(String[] args) {
       //Ich rufe getAge zweimal auf, daher wird 2 angezeigt
       getAge().bind(__ -> 
       getAge().bind(age -> {
       System.out.println(age);
       return unit(null);
       })).func.apply(0);
   }

}

Java-Monaden sind ein bisschen (ziemlich?) Schwer zu erkennen ... Java-Grenzen

Wenn Sie denselben Prozess ohne Verwendung der Statusmonade schreiben, sieht er folgendermaßen aus

public class NonMonadicExample {
    private static int age = 0;
    public static int getAge() {
        age = age + 1; //Ich bemerke die Existenz dieser Nebenwirkung nicht! !!
        return age;
    }

    public static void main(String[] args) {
        //Ich rufe getAge zweimal auf, daher wird 2 angezeigt
         getAge();
         System.out.println(getAge());
    }

}

Scala ist einfacher zu schreiben

In funktionalen Sprachen gibt es einen speziellen Syntaxzucker, der das Schreiben von DSLs in Sprachen erleichtert, die mit monadischen Mustern erstellt wurden. Mit Scala können Sie so mit Syntaxzucker schreiben, der Monad DSL gewidmet ist.

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

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

Wenn Sie mehr über andere Monadenmuster als staatliche Monaden erfahren möchten, lesen Sie Bücher wie "Scala Functional Design & Programming"! https://www.amazon.co.jp/dp/B00WM54V5Q/

"Aber ... Monade ist eine funktionale Sprache, nicht wahr? Es ist mir egal ..."

Das kann ich nicht sagen ~ Optionale Typen, CompletableFuture-Typen, von Java8 hinzugefügte StreamAPI und Observable of RxJava (Bibliothek für reaktive Programmierung), die in letzter Zeit beliebt ist, sind tatsächlich im Monadenmuster implementiert. Es ist schwer zu schreiben, da es keine dedizierte Syntax wie Scala gibt.

Außerdem scheint es die folgende Bibliothek als Mechanismus zu geben, um das Schreiben von Monaden in Java zu vereinfachen. 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