2012-12-14 11 views
5

Ich habe durch die great good Buch gearbeitet, aber ich kämpfe leicht mit Applicative Functors.Applicative Funktoren und links von entweder

Im folgenden Beispiel wird max auf den Inhalt der beiden Maybe Funktoren angewendet und gibt Just 6 zurück.

max <$> Just 3 <*> Just 6 

Warum im folgenden Beispiel wird Left "Hello" statt die Inhalte der Entweder functors zurückgegeben: Left "Hello World"?

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

Es ist eine traditionelle Verwendung von entweder, dass Right einen Wert darstellt, der Sie interessiert, während Left einen Fehler darstellt. Richtige (korrekte) Werte können mit Applicative und Functor kombiniert und modifiziert werden, während ein Wert für Links über schlecht hartnäckig beibehalten wird, also ist es gut für Dinge wie das Melden des ersten Fehlers, wie ein einfacher Compiler. – AndrewC

Antwort

10

Es ist, weil der Typ-Parameter in der Functor Instanz (und Applicative etc.) der zweite Typ Parameter ist. In

Either a b 

der a Typ und die Left Werte werden nicht von funktoriellen oder applicative Operationen betroffen, da sie Fehlerfälle oder auf andere Weise nicht zugänglich angesehen werden.

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

Verwenden Right,

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

zu Verkettung zu erhalten.

+0

Wenn Sie die Typvariablen umdrehen möchten, können Sie das Modul 'Data.EitherR' aus dem Paket' errors' verwenden. Dies bietet zwei Optionen: 'fliE', der ein Argument' Entweder' oder 'EntwederR' umlegt, das es in einen neuen Typ umwandelt, der die Variablenreihenfolge vertauscht und die symmetrischen Instanzen' Functor' und 'Applicative' ergibt. –

6

Daniels ausgezeichnete Antwort hinzuzufügen, gibt es ein paar Punkte, die ich würde gerne machen:

Zuerst here's die Applicative Beispiel:

instance Applicative (Either e) where 
    pure    = Right 
    Left e <*> _ = Left e 
    Right f <*> r = fmap f r 

Sie können sehen, dass dies ‚kurz- circuiting '- sobald es eine Left trifft, bricht es ab und gibt diese Linke zurück. Sie können dies mit der Strenge-Analyse des armen Mannes überprüfen:

Zweitens ist Ihr Beispiel ein wenig schwierig. Im Allgemeinen sind der Typ der Funktion und die e in Either e nicht verwandt. Hier ist <*> s Typ:

(<*>) :: Applicative f => f (a -> b) -> f a -> f b 

Wenn wir die Substitution f machen - >>Either e, erhalten wir:

(<*>) :: Either e (a -> b) -> Either e a -> Either e b 

Obwohl in Ihrem Beispiel e und a Spiel, in der Regel werden sie nicht Dies bedeutet, dass Sie eine Applicative-Instanz für Either e nicht polymorph implementieren können, die die Funktion auf ein linkes Argument anwendet.