Nach meiner Erfahrung sind Applikative Funktoren aus folgenden Gründen großartig:
Bestimmte Arten von Datenstrukturen lassen mächtige Arten von Kompositionen zu, können aber nicht wirklich zu Monaden gemacht werden. Tatsächlich fallen die meisten Abstraktionen in der funktionalen reaktiven Programmierung in diese Kategorie. Während wir technisch in der Lage sein könnten, zB Behavior
(aka Signal
) eine Monade zu machen, kann dies normalerweise nicht effizient durchgeführt werden. Applikative Funktoren ermöglichen es uns, immer noch kraftvolle Kompositionen zu haben, ohne die Effizienz zu beeinträchtigen (zugegebenermaßen ist es manchmal etwas schwieriger, ein Applikativ als eine Monade zu verwenden, nur weil Sie nicht so viel Struktur haben, mit der Sie arbeiten können).
Das Fehlen einer Datenabhängigkeit in einem anwendbaren Funktor ermöglicht es Ihnen, z. B. eine Aktion zu durchlaufen, um nach allen möglichen Effekten zu suchen, ohne dass die Daten verfügbar sind. Sie können sich also ein "Webformular" -Anwendungsprodukt vorstellen, das wie folgt verwendet wird:
userData = User <$> field "Name" <*> field "Address"
und Sie könnten eine Engine schreiben, die alle verwendeten Felder durchsucht und in einem Formular anzeigt. Wenn Sie die Daten zurückerhalten, führen Sie sie erneut aus, um die erstellten zu erhalten User
. Dies kann nicht mit einem einfachen Funktor (weil er zwei Formen zu einer kombiniert) oder einer Monade durchgeführt werden, da man mit einer Monade Folgendes ausdrücken könnte:
userData = do
name <- field "Name"
address <- field $ name ++ "'s address"
return (User name address)
Dies kann nicht gerendert werden, da der Name des zweiten Felds nicht bekannt ist, ohne dass bereits die Antwort des ersten Felds vorliegt. Ich bin mir ziemlich sicher, dass es eine Bibliothek gibt, die diese Formularidee umsetzt - ich habe meine eigene ein paar Mal für dieses und jenes Projekt gerollt.
Das andere schöne an anwendungsbezogenen Funktoren ist, dass sie komponieren . Genauer gesagt, der Kompositionsfunktor:
newtype Compose f g x = Compose (f (g x))
ist anwendbar, wann immer f
und g
sind. Das Gleiche gilt nicht für Monaden, die die gesamte Geschichte der Monadentransformatoren hervorgebracht haben, die auf unangenehme Weise kompliziert ist. Applikatoren sind auf diese Weise super sauber und es bedeutet, dass Sie die Struktur eines Typs aufbauen können, den Sie benötigen, indem Sie sich auf kleine zusammensetzbare Komponenten konzentrieren.
Kürzlich wurde die ApplicativeDo
Erweiterung in GHC veröffentlicht, mit der Sie die do
Notation mit Applikativen verwenden können, wodurch ein Teil der Komplexität der Notation verringert wird, solange Sie keine monadischen Dinge tun.