2014-11-05 8 views
10

Ich habe die folgende Methode:Idiomatische Art, ersteRightOrLinks in Haskell zu schreiben?

firstRightOrLefts :: [Either b a] -> Either [b] a 
firstRightOrLefts eithers = 
    case partitionEithers eithers of 
     (_, (x : _)) -> Right x 
     (xs, _)  -> Left xs 

Was mich stört, ist das hässliche Pattern-Matching und ich frage mich, ob es eine idiomatische Weise war diese Methode zu schreiben. Die Idee ist, dass ich eine Reihe von Berechnungen habe, die Eithers zurückgeben können und ich möchte nur das erste oder alle Fehlermeldungen erhalten. Vielleicht verwende ich die falsche Datenstruktur. Vielleicht wäre die Writer-Monade für diese Aufgabe besser geeignet. Ich bin mir zu diesem Zeitpunkt wirklich nicht sicher. Prost für jede Hilfe!

Antwort

16

Die umgekehrte Konvention ist eigentlich nur die Monade Definition für Either und die Definition für sequence ist ausreichend für diese: eigentlich

ghci> :t sequence :: [Either a b] -> Either a [b] 
sequence :: [Either a b] -> Either a [b] 
    :: [Either a b] -> Either a [b] 

zu Wenden Sie dieses auf Ihren Fall an, wir würden deshalb eine Funktion flipEither benötigen:

firstRightOrLefts = fe . sequence . map fe 
    where fe (Left a) = Right a 
      fe (Right b) = Left b 
+0

Das ist eigentlich eine brillante Antwort, es ist einfach und prägnant. Lassen Sie es für einen weiteren Tag offen für den Fall, dass es eine einfachere Antwort gibt, aber ansonsten akzeptiere ich das als Antwort. –

+2

Ich meine, Sie können auch Ihre als 'firstRightOrLefts = go [] schreiben, wobei acc e = case e von [] -> Left (reverse acc); (Richtig): es -> Richtig r; (Links l): es -> geh (l: acc) es, wenn du willst. Was ich an der obigen Antwort wirklich mag ist, dass es zeigt, dass Sie wahrscheinlich die Monade (zumindest in dieser Operation) in einer Weise verwenden, die der normalen Arbeitsweise der Leute entgegengesetzt ist: Sie wollen Fehler ansammeln und auf den ersten Erfolg warten Ihr Use-Case ist umgedreht, verglichen mit Leuten, die beim ersten Fehler aufhören wollen. Es ist wahrscheinlich egal, aber wenn Sie einen Parser schreiben, ist das nützlich zu wissen! –

+8

Sie können auch 'fe = entweder Right Left' schreiben. –

9

Die MonadPlus Instanz für Except hat dieses Verhalten:

import Control.Monad 
import Control.Monad.Trans.Except 

firstRightOrLefts :: [Either e a] -> Either [e] a 
firstRightOrLefts = runExcept . msum . fmap (withExcept (:[]) . except) 
+0

Das ist ziemlich nett. Zumal es Standardoperatoren verwendet, um die Arbeit zu erledigen. Ich werde den Typen weiter folgen, um zu sehen, wie es funktioniert. –