Monade (Informatik)
# Monade (Informatik)

In der funktionalen Programmierung sind Monaden ein abstrakter Datentyp. Wesentliche Eigenschaft von Monaden ist die Fähigkeit der Übertragung von Werten und Berechnungen eines „einfacheren“ Typs zu Berechnungen eines „höheren“ Typs, der mittels eines Typkonstruktors aus dem einfacheren Typ hervorgeht, sowie die Verknüpfung mehrerer solcher Übertragungen zu einer einzigen.

## Hintergrund

Der Hauptnutzen von Monaden ist es, Ein- und Ausgabeoperationen, zustandsbehaftete Berechnungen, Nichtdeterminismus (auch als Iteration über Kollektionen und ihren Kombinationen interpretierbar) und Anderes auszudrücken. Dabei soll die Sprache keine Nebeneffekte einführen.

Das Konzept der Monade stammt aus der Kategorientheorie, einem Zweig der Mathematik, welcher mathematische Objekte mittels Morphismen oder Funktoren vergleicht. Die Wörter Monade oder aber auch Funktor sind wiederum von Konzepten in der Philosophie abgeleitet.

Die Programmiersprache Haskell ist eine funktionale Sprache, die Monaden stark einsetzt und versucht, monadische Kompositionen zu vereinfachen, beispielsweise durch syntaktischen Zucker (u. a. die sogenannte do-Notation).

## Definitionen

Die übliche Formulierung einer Monade in der Programmierung hat folgende Komponenten:

* Ein Typkonstruktor, der für jeden zugrunde liegenden Typ definiert, wie der korrespondierende Monadentyp zu erhalten ist. Der Name dieses Typkonstruktors wird dabei oft synonym mit der ganzen Monade verwendet. Wenn M der Name der Monade und t der Datentyp ist, so ist M t der korrespondierende monadische Typ.
* Eine Einheitsfunktion, die einen Wert des zugrunde liegenden Typs auf den Wert des korrespondierenden Monadentyps abbildet. Das Ergebnis ist der "einfachste" Wert im korrespondierenden Typ, der sich aus dem Originalwert gewinnen lässt. In Haskell wird diese Funktion return genannt. Die Einheitsfunktion hat den polymorphen Typ t→M t.
* Mindestens eine weitere Operation (siehe dazu die folgenden Abschnitte), welche die Verknüpfung monadischer Operationen beschreibt.

Die folgenden Operationen sind typisch für Monaden und können für deren Definition Verwendung finden:

* Die Einheitsfunktion return :: a -> m a
* Der bind-Operator (>>=) :: m a -> (a -> m b) -> m b erlaubt, einen monadischen Typ an eine Funktion zu übergeben, die nur den zugrundeliegenden Typ verwendet. Sein erstes Argument ist ein Wert von monadischem Typ und sein zweiter ist eine Funktion, die vom zugrunde liegenden Typ des ersten Arguments auf einen anderen monadischen Typ abbildet. Der Rückgabewert ist vom anderen Monadentyp.
* Der Kleisli-Operator (>=>) :: (a -> m b) -> (b -> m c) -> (a -> m c) realisiert eine Komposition (Hintereinanderausführung) für Funktionen, die einen monadischen Typ zurückgeben, aber nur den jeweils zugrundeliegenden Typ verwenden.
* Der Funktor fmap :: (a -> b) -> m a -> m b erlaubt, einen monadischen Typ an eine Funktion zu übergeben, die nur den zugrundeliegenden Typ verwendet. Sein erstes Argument ist eine Funktion f, von einem beliebigen Typ a auf einen beliebigen Typ b abbildet. Sein zweites Argument ist ein Wert von einem monadischen Typ, dem der Typ a des Argumentes von f zugrunde liegt. Der Rückgabewert ist von einem monadischen Typ, dem der Typ b des Rückgabewertes von f zugrunde liegt.
* Eine natürliche Transformation join :: m (m a) -> m a welche ein „Abflachen“ des monadischen Typs um eine Verschachtelungsebene erlaubt (dabei steht m für den Typkonstruktor).

Diese Operationen müssen folgenden Gesetzen gehorchen:

* "Assoziativität" von >>= (ma >>= f) >>= g == ma >>= ( \a -> ((f a) >>= g) )
* Assoziativität von >=> (f >=> g) >=> h == f >=> (g >=> h)
* Kompatibilität von Verkettung und fmap fmap (f . g) == (fmap f) . (fmap g)
* join ist eine natürliche Transformation von fmap . fmap auf fmap (fmap f) . join == join . ((fmap . fmap) f)
* Kommutativität von fmap und join join . join == join . (fmap join) -- das zweite join hat den typ m (m (m a)) -> m (m a)
* return ist eine natürliche Transformation von id auf fmap (fmap f) . return == return . f
* Neutralität von return unter >>= ma >>= return == ma (return a) >>= f == f a
* Neutralität von return unter >=> f >=> return == return >=> f == f
* Neutralität von return unter >=>, in fmap/join-Notation join . return == join . (fmap return) == id

### In Anlehnung an Haskell

In Haskell wird eine Monade über die Operationen return und (>>=) definiert:

Die anderen Operationen lassen sich dann über diese beiden definieren:

### Über den Kleisli-Operator

Eine Monade lässt sich auch über ihre Kleisli-Kategorie definieren:

Die übrigen Operationen ergeben sich dann wie folgt:

### Analog zur Kategorientheorie

In der Kategorientheorie wird eine Monade üblicherweise über einen Funktor fmap sowie zwei natürliche Transformationen return und join definiert:

Die übrigen Operationen lassen sich dann wie folgt realisieren:

## Beziehungen zu anderen Typklassen

Jede Monade ist auch ein Applikativer Funktor und mithin auch ein Funktor. Umgekehrt gilt das nicht.

Diese Eigenschaft fand sich aus historischen Gründen nicht explizit in Haskells Standardbibliothek, der Glasgow Haskell Compiler hat dies jedoch mit Version 7.10 eingeführt.

Besonders deutlich wird diese Beziehung auch, vergleicht man die kategorientheoretische Definition mit der Funktor-Klasse in Haskell:

Dabei muss fmap ebenfalls die Kompatibilitätsbedingung mit der Komposition (.) erfüllen.

## Beispiele

### Behälter

Container wie Listen, Mengen, Multimengen stellen Monaden dar, deren Bindeoperation die übergebene Funktion auf alle Elemente anwendet und die dabei erhaltenen Ergebnisse vereinigt. Die Vereinigungsoperation ist dabei jeweils Listenverkettung, Vereinigungsmengenbildung bzw. Bildung der Multimengenvereinigung. Die Einheitsfunktion ergibt Einermengen und -listen.

Hier als Beispiel die Monade für verkettete Listen. Das Konzept der Instanz für Listen ist es, eine Liste einzulesen, dann jedes Element an die Funktion zu übergeben und die Ergebnisse zu verbinden. Hier eine Beispielimplementation in Haskell:

### Vektoren und lineare Abbildungen

Der Typkonstruktor bildet hier einen Typ $T$ auf einen Vektorraum $V(T)$ ab, bei dem $T$ als (Namensgeber für eine) Basis dient, und dessen Elemente beispielsweise als Funktionen $T\to \mathbb {R}$ modelliert werden. Die Bindeoperation hat den Typ $V(T)\to (T\to V(U))\to V(U)$. Durch Vertauschen der Argumente erhält man den Typ $(T\to V(U))\to (V(T)\to V(U))$, an dem man die Semantik erkennen kann: die gegebene Funktion, die auf den Basiselementen definiert ist, wird zu einer vollen linearen Abbildung erweitert. Die Einheitsfunktion bildet das Basiselement (welches in dieser Modellierung noch kein „richtiger“ Vektor ist) auf den entsprechenden Basisvektor ab.

### State, I/O

Bei zustandsbehafteten Aktionen dient die Bindeoperation der Verwirklichung der Hintereinanderausführung. Die Einheitsfunktion erstellt eine Aktion, die nichts tut und ein festes Resultat zurückgibt.

Das Konzept ist dabei recht natürlich. Wenn man in einer rein funktionalen Programmiersprache einen veränderlichen Status übergeben will, dann macht man das in der Regel auf folgende Weise, hier am Beispiel einer Zählerfunktion:

Das Grundprinzip ist, dass man als Parameter den alten Status anhängt und den neuen mit dem Rückgabewert zusammen zurückgibt. Um sich Arbeit zu ersparen, kann man dieses Muster einfach in einen neuen Typen verpacken, der Parameter s des Types ist der Typ des Status, a ist der Parameter des Rückgabewertes:

Was man jetzt noch braucht, sind ein paar Funktionen, die den Status manipulieren können. Hier zum Beispiel eine Funktion, die den Status auf einen neuen setzt, und eine, die ihn ausliest:

Dies ist schon fast alles, was nötig ist. Das einzige, was noch fehlt, ist die Möglichkeit mehrere statusverändernde Aktionen zu kombinieren, hier sind Monaden das Werkzeug der Wahl:

Mit diesen Funktionen und dem syntaktischen Zucker der do-Notation (der die monadischen Operationen vor uns versteckt) lässt sich das Beispiel dann folgendermaßen formulieren:

## Andere Sprachen

LINQ-Abfrageausdrücke in C# sind direkt inspiriert von Haskells do-Notation. Ein Analogon zur Typklasse Monad ist in C# jedoch nicht ausdrückbar; der Compiler übersetzt LINQ-Abfrage-Ausdrücke blind in Aufrufe von Methoden mit festgelegten Namen. Diese sind Select und SelectMany. Auch benutzerdefinierte Klassen können also mittels LINQ-Abfrageausdrücken angesprochen werden, wenn diese Methoden mit entsprechenden Namen zur Verfügung stellen.

Dieselbe Strategie verfolgt Scala im Fall von for-Comprehensions. Die Methoden heißen da map und flatMap.

In der Standardbibliothek von Java 8 sind mindestens zwei Monaden vorhanden, die derselben Namenskonvention gehorchen: die Schnittstellen Optional und Stream definieren Methoden namens map, flatMap und of.

