Warum tippt dieser entweder Monad-Code nicht die Prüfung ein?
Frage
instance Monad (Either a) where
return = Left
fail = Right
Left x >>= f = f x
Right x >>= _ = Right x
Dieser Code -Frag in 'baby.hs' verursachte den schrecklichen Kompilierungsfehler:
Prelude> :l baby
[1 of 1] Compiling Main ( baby.hs, interpreted )
baby.hs:2:18:
Couldn't match expected type `a1' against inferred type `a'
`a1' is a rigid type variable bound by
the type signature for `return' at <no location info>
`a' is a rigid type variable bound by
the instance declaration at baby.hs:1:23
In the expression: Left
In the definition of `return': return = Left
In the instance declaration for `Monad (Either a)'
baby.hs:3:16:
Couldn't match expected type `[Char]' against inferred type `a1'
`a1' is a rigid type variable bound by
the type signature for `fail' at <no location info>
Expected type: String
Inferred type: a1
In the expression: Right
In the definition of `fail': fail = Right
baby.hs:4:26:
Couldn't match expected type `a1' against inferred type `a'
`a1' is a rigid type variable bound by
the type signature for `>>=' at <no location info>
`a' is a rigid type variable bound by
the instance declaration at baby.hs:1:23
In the first argument of `f', namely `x'
In the expression: f x
In the definition of `>>=': Left x >>= f = f x
baby.hs:5:31:
Couldn't match expected type `b' against inferred type `a'
`b' is a rigid type variable bound by
the type signature for `>>=' at <no location info>
`a' is a rigid type variable bound by
the instance declaration at baby.hs:1:23
In the first argument of `Right', namely `x'
In the expression: Right x
In the definition of `>>=': Right x >>= _ = Right x
Failed, modules loaded: none.
Warum passiert das? Und wie könnte ich diesen Code kompilieren lassen? Danke für jede Hilfe ~
Aha. Und ich habe den Code angepasst, um ihn zu erstellen:
instance Monad (Either a) where
return = Right
Left a >>= f = Left a
Right x >>= f = f x
Es kompiliert erfolgreich! Aber ... für eine weitere Frage:
instance Monad (Either a)
macht 'entweder ein' a monad und ich habe 'return = rechts' ... wie könnte ich 'return = links' bekommen? Ich habe es versucht, aber gescheitert:
instance Monad (`Either` a) where
return = Left
Right a >>= f = Right a
Left x >>= f = f x
oder: Instanzmonade ( x -> entweder xa)
Kompiliert überhaupt nicht!
Lösung
- Rückgabe sollte Typ haben
forall b. b -> Either a b
, Allerdings hat der Typforall c. a -> Either a c
. Sie wollen wahrscheinlich hier. fail
sollte Typ habenforall b. String -> Either a b
, Allerdings hat richtig Typforall b. b -> Either a b
, also wennb=String
das machtString -> Either a String
was nicht passt.>>=
sollte Typ habenEither a b -> (b -> Either a c) -> Either a c
jedochRight x >>= _ = Right x
Gibt immer einen Wert des Typs zurückEither a b
, nichtEither a c
.Left x >>= f = f x
Funktioniert nicht, weil x Typ hata
, aberf
hat Typb -> c
.
Andere Tipps
Der größte Teil der Verwirrung ergibt sich aus der Tatsache, dass links und rechts nach hinten verwendet werden. In Anbetracht des Typs für die Rückkehr lautet sein Typ aus der Monadentypklasse wie folgt:
return :: (Monad m) => b -> m b
Sie versuchen, eine Instanz für zu definieren m
= Either a
, also sollte die Rückgabe einen Typ haben:
return :: b -> Either a b
Sie definieren es als übrig, was einen Typ hat:
Left :: a -> Either a b
Beachten Sie, wie die linke Seite des ->
unterscheidet sich.