- http://weblogs.asp.net/podwysocki/archive/2008/10/13/functional-net-linq-or-language-integrated-monads.aspx: "Simply put, a monad, unlike your normal function results, stores function results and side-effect representations. This allows side effects to be propagated through the return values of functions without breaking the pure functional model."
- http://www.reddit.com/r/programming/comments/64th1/monads_in_python_in_production_code_you_can_and/c02u9mb: "For example, it is possible to write out messages in a purely functional way using a monad. The idea is, instead of just returning a value, you return a value and the string that you want to write to the screen. Why do it that way, instead of just writing out to the screen? Because that way, your functions don't have side-effects, you preserve referential transparency, and you -- and more importantly, your compiler -- can reason about your code algebraically, allowing it to simplify your code the way you would an equation."
- http://www.haskell.org/tutorial/monads.html, "What [Monads] really provide is modularity. That is, by defining an operation monadically, we can hide underlying machinery in a way that allows new features to be incorporated into the monad transparently."
- http://www.inf.fu-berlin.de/lehre/SS09/PI02/docs/monaden.pdf, "Monaden sind einfach eine Möglichkeit, Funktionen elegant miteinander zu kombinieren, bei denen es auf Grund ihrer Typen zu Problemen bei der Benutzung der normalen Funktionskomposition kommt."
- http://www.algorithm.com.au/downloads/talks/monads-are-not-scary/monads-are-not-scary-chak.pdf, “Monads are a programming pattern for library APIs. […] What kind of libraries benefit from monads? Answer: Libraries that manipulate contextual information. Contextual information is implicit and the monad hides it.”
- http://channel9.msdn.com/shows/Going+Deep/Brian-Beckman-Dont-fear-the-Monads/ (sehr empfehlenswertes Video zur funktionalen Programmierung im Allgemeinen und Monaden im Besonderen)
- http://leibnizdream.wordpress.com/2008/10/21/why-use-computation-workflows-aka-monads-in-f/
- http://www.paul-abraham.com/MonadsInFSharp.doc
- http://blogs.msdn.com/wesdyer/archive/2008/01/11/the-marvels-of-monads.aspx
- http://codebetter.com/blogs/matthew.podwysocki/archive/2009/01/28/much-ado-about-monads-maybe-edition.aspx
- http://www.aboutcode.net/2008/01/14/Async+WebRequest+Using+LINQ+Syntax.aspx
- http://codebetter.com/blogs/matthew.podwysocki/archive/2009/12/30/much-ado-about-monads-state-edition.aspx
- http://community.bartdesmet.net/blogs/bart/archive/2008/08/19/probably-the-most-powerful-linq-operator-selectmany.aspx (zur Rolle von SelectMany() für Monad-Implementationen in C#)
- http://higherlogics.blogspot.com/2008/01/almost-type-safe-general-monad-in-c-aka.html
- http://blog.sigfpe.com/2006/10/monads-field-guide.html (interessante Visualisierung von Monads)
- http://www.haskell.org/haskellwiki/Monad_tutorials_timeline (Linksammlung von Monad Tutorials)
- http://www.haskell.org/haskellwiki/What_a_Monad_is_not (zur Abgrenzung)
Wie würde ich nun Monads erklären? Hm... mal sehen. In einem zukünftigen Beitrag versuche ich das mal.
7 Kommentare:
Hi Ralf,
anbei ein weiterer Link mit Beiträgen über Monads.
A Neighborhood of Infinity
Mir ist auch noch nicht 100% klar was es mit Monads auf sich hat. Einen Monad zeichnet u.a. aus, dass man bestimmte Operatoren (z.B. Bind) auf ihm definieren kann.
In meinem Verständnis sind Monads Patterns der funktionalen Programmierung.
Es gibt ja nicht nur DEN Monad sondern mehre Typen z.B. den Continuation Monad, Maybe Monad, State Monad etc.
Benjamin
So weit mir das klar ist (ich bin allerdings C#-Entwickler und kein Haskell oder F#-Entwickler) ist der Grundgedanke von Monaden, dass verhindern von Verunreinigungen einer reinen Funktionen (http://msdn.microsoft.com/de-de/library/bb669139.aspx). Diese zeichnen sich ja unter anderen durch ihre Freiheit von Neben- bzw. Seiteneffekten, wie bsw. IO, aus. Nun ist ein Programm ohne IO in der Praxis so ziemlich sinnlos und deshalb können eine ganze Reihe von Monaden (IO, State, usw.) als Kapselung der Seiteneffekte an die reine Funktion übergeben werden. Wie das in C# elegant bewerkstelligt werden kann (Schön wär's!), frag ich mich im Augenblick allerdings auch.
@Mike: Mit deiner Beschreibung hast du natürlich Recht. Es bleibt die Frage: Warum der Aufstand, "Verunreinigungen" zu vermeiden?
Meine Antwort derzeit: Es geht um Composability. Ohne Monaden hab ich es schwerer, den Effekten einer "Computation" zu folgen. Ich sehe den Schritten nicht wirklich an, was sie für Effekte haben. Die sind nicht "zentralisiert", sondern können alles mögliche betreffen.
Mit einer Monade aber schaffe ich einen "Container" für Effekte jenseits der Berechnung einer Funktion (z.B. Ausgaben in Dateien, Fehlerinformationen).
Für die Dauer einer "Computation" ist die Monadeninstanz der Kontext. Er umschließt die "Computation" oder er spannt einen Raum für sie auf.
Deshalb spricht Brian Beckman auch immer mal wieder davon, dass ein OS Prozess oder auch eine CLR Instanz mit ihrem Hauptspeicher eine "ambient monad" sei.
In C# ist IEnumerable eine Monade, auf der Operationen mit LINQ ausgeführt werden. Insb SelectMany() ist dafür ein Ausdruck.
Ich grübel mal weiter an einem knackigeren Beispiel als dem, was normalerweise so gegeben wird. Identity oder Maybe Monaden find ich nicht so spannend.
-Ralf
@Ralf: Nun, mmmhh, aha ja OK. Ich bin konzeptionell immer davon ausgegangen, dass Monaden reine Funktionen über Argumente erweitern und damit die effektfreie Komposition von Operationen ermöglicht wird. (Wie gesagt ist mir der genaue praktische Einsatz von Monaden unklar.) Das es durch einen Raum, besser gesagt äußeren Kontext, geschehen kann ist mir nicht in den Sinn gekommen.
Kann das mal laut gedacht folgendes heißen?
Ein IO-Monad, bsw. ConsoleOut-Monad, stellt einen Raum/Kontext zur Verfügung. Jedes Ergebnis der Funktionen (evtl. Funktions-Pipelines) innerhalb des IO-Monad-Kontextes werden unweigerlich zu einer Konsolen-Ausgabe führen?
Und warum ist SelectMany() im Vergleich zu Select/Map so besonders?
@Mike: So wie ich Monaden derzeit verstehe, spannen sie einen Raum auf (oder sagen wir Container), der sich auf eine "Computation" bezieht, also auf eine Schrittfolge von Anweisungen.
Statt, dass die Anweisungen globale Seiteneffekte haben (oder ist das ein Pleonasmus?), nehmen sie nur Veränderungen an der Monade vor, d.h. an dem ihnen zugewiesenen Container.
Dieser Container wird von Schritt zu Schritt quasi automatisch weitergereicht; das macht die Monade aus. Monaden sind also temporäre lokal-globale Sandkästen für Seiteneffekte.
Sie sind global für die Schritte einer "Computation". Aber sie sind lokal, weil sie eben nicht über sie hinaus existieren.
Beispiel:
var x = new[] {1, 2, 3, ...}.Select(...).Where(...).Select(...);
Die Monade ist das IEnumerable, das von Schritt zu Schritt "fließt". Es ist ein lokal, weil es nur hier existiert. Es ist aber global für alle Schritte.
Das es im Detail immer unterschiedliche IEnums sind und die keinen weiteren Zustand über irgendwelche Zahlen hinaus haben, ist nur ein Sonderfall.
-Ralf
Vielen Dank! Könnte man sagen, dass das einem durchreichen (fließen) eines Objektes (des Monaden), bzw. dessen konkrete Repräsentation, durch reine Funktionen (globaler Kontext des Monaden) entspricht und diese Funktionen den internen/lokalen Zustand/Eigenschaft(en) des Objektes oder dessen derzeitige Repräsentation bei jedem Schritt auf die nächste Operation ändern?
Nun, sehr interessant. Sehr schön finde ich die Idee, den Objektzustand vom Objektverhalten komplett getrennt zu sehen. Damit ergibt sich die Möglichkeit, dass korrekte Verhalten einer Funktion über eine Prüfung des Objektzustandes zu testen. Dennoch fallen mir, bis auf IQueryable und eigene Domänen-Modelle, keine weiteren "monadischen" C#-Standard-Typen für weitere Praxisbezüge ein.
Mike
@Mike: Ja, ich denke, so ist das: Die Monade fließt durch die Schritte einer "Computation". Und diese Schritte verändern die Monade bzw. erzeugen immer neue Monaden anderen Typs.
Nun könnte man ja aber sagen: Dann machen wir einfach eine normale Klasse pro "Computation", geben der die Schritte der "Computation" als Methoden und rufen die Methoden nacheinander auf. Je "Computation" Aufruf wird eine Instanz der Klasse erzeugt, damit deren Zustand lokal-global ist.
Das würde gehen - ist aber nur die Variante für arme Leute ;-) Denn der fehlt die entscheidende Motivation der Funktionalen Programmierung: Composability.
Die Schritt-Methoden einer solchen Klasse ließen sich eben nicht in anderen Zusammenhängen wiederverwenden. Das ist aber der Trick der Monade! Sie bietet mit Bind() einen Mechanismus, der immer wieder neuen Funktionen erlaubt, "an ihr teilzunehmen". So wie bei LINQ: Da kann ich mit den Extension Methods beliebig viele Select() Aufrufe hintereinander schalten (die jeder für einen neuen Schritt stehen). An IEnum ändert das nichts.
-Ralf
Kommentar veröffentlichen