Ich frage mich, ob es ein Äquivalent oder etwas für null
aus Listen gibt, die für Monaden verallgemeinert wurden. Im Moment versuche ich mit == mzero
fehlerhafte Werte zu finden. Aber diese Art der Überprüfung provoziert falsch positive Ergebnisse, da mzero /= Left "foo"
gilt.
Gibt es eine elegante Möglichkeit, was ich in Standardbibliotheken ausdrücken möchte?
Der Begriff "enthält einen Wert" wird nicht von der Typklasse Monad
erfasst. Immerhin gibt dir Monad
nur etwas, um Aktionen zu sequenzieren ( >>=
) (bind das vorherige Ergebnis). Und MonadPlus
gibt Ihnen die Möglichkeit, eine Berechnung mit mzero
zu "verkürzen" (schauen Sie sich die Gesetze an und mplus
).
Allerdings ist es in der Regel möglich, einen oder mehrere Werte zu enthalten, um alle diese Werte zu etwas zusammenfalten zu können. Und tatsächlich enthält Data.Foldable
eine Funktion, die auch als null
bezeichnet wird:
Ergebnis:
%Vor% Was Sie suchen, ist Teil von Foldable
, nicht Monad
. Dies funktioniert nur mit GHC 7.10 oder höher, da Data.Foldable.null
in Basis 4.8.0.0 eingeführt wurde. Wenn Sie mit einer älteren Version von GHC festgefahren sind, können Sie
Ich kann mich an keiner Stelle an eine einfache Funktion erinnern, die für alle Monaden funktioniert. Maybe
, Either e
, MaybeT m
und ExceptT e m
, welche die Hauptmonaden sind, die "fehlerhafte Werte" haben.
Da GHC 7.10, null
tatsächlich verallgemeinert wurde (auf Foldable
), funktioniert es bei den ersten beiden.
Für die letzten drei ( Either e
arbeitet mit beiden Methoden) und transformierte Versionen von ihnen, können Sie wahrscheinlich die catchError
Funktion.
(Obwohl die letzten beiden %
Definitiv nicht von außerhalb der Monade. Wenn Sie nach etwas wie nonEmpty :: MonadPlus m => m a -> Bool
suchen, dann ist es unmöglich.
Sie müssten die monadische Berechnung tatsächlich ausführen, um herauszufinden, ob sie "leer" ist. Aber die Monade benötigt möglicherweise eine Art von Eingabe zum Ausführen (z.B. Dinge wie State
oder sogar nur Reader
), und im Extremfall von IO
kann man die Monade überhaupt nicht von außen ausführen. Nun sind diese Beispiele nicht MonadPlus
auf ihrer eigenen AFAICR, sondern erweitern sie um Fehler (z. B. MaybeT
) und plötzlich gibt es eine offensichtliche Definition dessen, was es für sie bedeutet, "leer" zu sein, aber die gleichen Einschränkungen gelten immer noch. Da eine unbekannte Monade eine davon sein könnte, kann man keine Informationen herausbekommen.
Eine mögliche Signatur könnte nonEmpty :: MonadPlus m => m a -> m Bool
sein (obwohl ich mir nicht sicher bin, ob das auch eine sinnvolle Implementierung ist). Aber ich glaube nicht, dass Sie danach streben, denn es verallgemeinert nicht wirklich null
; Sie würden% cid_de% oder [False]
für Listen beenden (oder möglicherweise sogar [True]
mit der gleichen Anzahl von Elementen wie die Eingabe), was ein bisschen komisch ist.
Ich denke, Monaden sind auf der falschen "Generalisierungsachse" für [True, True, True, ...]
; Sie wollen eine Abstraktion, die Container besser charakterisiert als null
(viele Monaden sind Container, aber auch viele andere Dinge, die sehr unterschiedlich sind, so dass Code, der auf beliebigen Monaden funktioniert, nicht annehmen kann behälterähnliche Eigenschaften). Verallgemeinert auf Monad
, wie es in GHC-7.10 passiert ist, scheint eine ziemlich gute Wette zu sein. Sie könnten wahrscheinlich eine Foladable
type-Klasse erstellen, die ein paar mehr Dinge zulässt als CanBeEmpty
; Ich weiß nicht, dass so etwas schon existiert.
Die idiomatische Sache ist, nicht zu versuchen, die Null direkt zu erkennen, sondern das gewünschte Verhalten im Falle von Null zu liefern.
Dies ist mplus
oder äquivalent (in den letzten Preludes) <|>
do; Es kettet eine Aktion, die ausgeführt werden soll, falls die erste Aktion fehlschlägt. Dies ist das gleiche wie catchError
auf den Monaden, die catchError
unterstützt. Es ist analog zu dem allgemeinen Idiom in Shell oder Perl Programmierung% Co_de% Bedeutung Run Foo und dann Bar ausführen, wenn Foo fehlgeschlagen.
Beachten Sie in der Liste monad, dass es alle Optionen ausführen wird, denn so funktioniert die Listen-Monade, die "mehrere Möglichkeiten" modelliert.
Ich verwende häufig foo || bar
auf <|>
oder MaybeT
, um eine linksbündige Wahl zu modellieren, d. h. "versuche alle diese Alternativen der Reihe nach, bis einer Erfolg hat".
Beachten Sie, dass die Verwendung von EitherT
für <|>
die Fehlermeldung verwerfen kann (da eine fehlerhafte Berechnung in eine nachfolgende umgewandelt wird); Wenn Sie die Fehlermeldung speichern und irgendwie verarbeiten möchten, ist es wieder EitherT
, das Sie wollten.
Tags und Links haskell