Haskell Prüfe, ob ein Wert in Monad existiert

7

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?

    
bash0r 20.10.2015, 07:07
quelle

4 Antworten

12

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:

%Vor%

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

verwenden %Vor%     
Zeta 20.10.2015, 07:34
quelle
5

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 % Foldable die falsche Sache.)

    
Ørjan Johansen 20.10.2015 07:32
quelle
5

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.

    
Ben 20.10.2015 07:58
quelle
2

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.

    
drquicksilver 20.10.2015 11:15
quelle

Tags und Links