Per aggiungere alla risposta eccellente di Daniel, ci sono un paio di punti mi piacerebbe fare:
In primo luogo, l'istanza here's applicativo:
instance Applicative (Either e) where
pure = Right
Left e <*> _ = Left e
Right f <*> r = fmap f r
si può vedere che questo è 'breve circuiting '- non appena raggiunge lo Left
, interrompe e restituisce quella sinistra. Puoi controllare questo con l'analisi della severità del povero:
ghci> (++) <$> Left "Hello" <*> undefined
Left "Hello" -- <<== it's not undefined :) !!
ghci> (++) <$> Right "Hello" <*> undefined
*** Exception: Prelude.undefined -- <<== undefined ... :(
ghci> Left "oops" <*> undefined <*> undefined
Left "oops" -- <<== :)
ghci> Right (++) <*> undefined <*> undefined
*** Exception: Prelude.undefined -- <<== :(
In secondo luogo, il tuo esempio è un po 'complicato. In generale, il tipo di funzione e lo in Either e
non sono correlati. Ecco <*>
s Tipo:
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
Se facciamo la sostituzione f
- >>Either e
, otteniamo:
(<*>) :: Either e (a -> b) -> Either e a -> Either e b
Anche se nel tuo esempio, e
e a
partita, in generale, non lo faranno , il che significa che non è possibile implementare polimorficamente un'istanza Applicativa per Either e
che applica la funzione a un argomento a sinistra.
fonte
2012-12-14 15:13:44
È un utilizzo tradizionale di Either Right rappresenta un valore a cui sei interessato, mentre Left rappresenta un errore. I valori giusti (corretti) possono essere combinati e modificati usando Applicativo e Functor, mentre un valore negativo di Left over si ostinerà a persistere, quindi è utile per cose come riportare il primo errore come potrebbe fare un semplice compilatore. – AndrewC