2016-04-10 11 views
2

die bei Werfen wir einen Blick:Unnötige Zuordnung in do Sequenz

instance (Error e) => MonadTrans (ErrorT e) where 
    lift m = ErrorT $ do 
    a <- m 
    return (Right a) 

Ich kann nicht verstehen, warum a <- m notwendig ist. Warum schreiben wir nicht nur:

instance (Error e) => MonadTrans (ErrorT e) where 
    lift m = ErrorT $ do 
    return (Right m) 

Antwort

3
m :: m a 
Right m :: Either e (m a) 
return (Right m) :: m (Either e (m a)) 
ErrorT $ return (Right m) :: ErrorT e m (m a) 

Dies hat den falschen Typ: wir wollten ErrorT e m a.

Stattdessen, wenn a <- m verwenden, die wir haben:

a :: a 
Right a :: Either e a 
return (Right a) :: m (Either e a) 
ErrorT $ return (Right a) :: ErrorT e m a 

, die in Ordnung ist.

(. Oberhalb einige Wertvariablen den gleichen Namen des Typs Variablen auf der rechten Seite von :: haben - das ist nur ein Vorfall)

Alternativen:

instance (Error e) => MonadTrans (ErrorT e) where 
    lift m = ErrorT $ fmap Right m 

oder mit applicative Notation,

instance (Error e) => MonadTrans (ErrorT e) where 
    lift m = ErrorT $ Right <$> m 
+0

Von Ihrem ersten Stück Code: 'zurück (Right m) :: * m * (Entweder e (ma))' Ich kann nicht verstehen, warum es m ist (ich hob es durch * m *) und nicht zum Beispiel 'ErrorT' – Gilgamesz

+0

@Gilgamesz Sie sind richtig: dass es eigentlich' n (Entweder e (ma)) 'für jede Monade' n' ist, die sich von 'm' unterscheiden kann. Das Endergebnis wäre dann "ErrorT ... :: ErrorT en (ma)", aber da "lift" 'ErrorT ema' zurückgeben muss, erzwingt dies" n = m "(und' ma = a', was unmöglich ist und löst einen Typfehler aus). Ich habe 'n = m' früher angewendet und bin etwas weniger allgemein. (und aus dem gleichen Grund sollte 'Right a'' entweder za' für alle 'z' sein, einschließlich denen, die sich von' e' unterscheiden, aber schließlich muss 'z' sowieso' e' sein) – chi

+0

Danke guten Mann :) – Gilgamesz

4

Sie lesen a <- m als "zuweisen a den Wert m." Diese Notation für die Zuweisung ist im Pseudocode üblich, bedeutet aber in Haskell etwas anderes. Sie können es lesen als "Produzieren Sie einen Wert von m und binden Sie diesen Wert an a." Um genauer zu sein, in einem do Block,

a <- m 
... 
... 

entspricht

m >>= \a -> 
    do 
    ... 
    ... 

So Anwendung Right-a sinnvoll ist, aber es m gibt Ihnen eine monadische Aktion eingewickelt in Either Anwendung, die ist normalerweise nicht das, wonach du suchst.

Es ist jedoch ein kürzerer Weg, um dieses Beispiel zu schreiben:

instance Error e => MonadTrans (ErrorT e) where 
    lift m = ErrorT (Right <$> m) 

Nota Bene: ErrorT hat im Allgemeinen durch die mehr allgemein nützlichen ExceptT verdrängt worden, was nicht die lästige hat und oft irrelevant Error Kontext. Insbesondere ist es oft nützlich, einen "Ausnahme" -Wert zu haben, der eigentlich keinen Fehler darstellt und keine Instanz von Show ist.

+0

danke auch :) – Gilgamesz