2012-12-14 15 views
5

Ho lavorato con il libro great good, ma sto leggermente combattendo con gli applicativi.Funzionalità applicative e sinistra da O

Nell'esempio seguente, max viene applicato al contenuto dei due tasti Funzioni e restituisce Just 6.

max <$> Just 3 <*> Just 6 

Perché nel seguente esempio viene restituito Left "Hello" invece dei contenuti dei funtori Entrambi: Left "Hello World"?

(++) <$> Left "Hello" <*> Left " World" 
+0

È 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

risposta

10

È perché il parametro tipo nei Functor caso (e Applicative etc.) è il secondo parametro di tipo. In

Either a b 

tipo a, ei valori Left non sono influenzati dalle operazioni funtoriali o applicative, perché sono considerate casi di insufficienza o altrimenti inaccessibili.

instance Functor (Either a) where 
    fmap _ (Left x) = Left x 
    fmap f (Right y) = Right (f y) 

Usa Right,

(++) <$> Right "Hello" <*> Right " World" 

per ottenere la concatenazione.

+0

Se si desidera capovolgere le variabili di tipo, è possibile utilizzare il modulo 'Data.EitherR' dal pacchetto' errors'. Questo fornisce due opzioni: 'flipE', che ribalta un argomento' Either' o 'EitherR' che lo avvolge in un newtype che scambia l'ordine delle variabili, dando le istanze simmetriche' Functor' e 'Applicative'. –

6

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.

Problemi correlati