Pourquoi ce code de l'une ou l'autre monade ne tape pas de vérification?
Question
instance Monad (Either a) where
return = Left
fail = Right
Left x >>= f = f x
Right x >>= _ = Right x
Ce code de code dans «baby.hs» a provoqué l'horrible erreur de compilation:
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.
Pourquoi cela arrive-t-il? Et comment pourrais-je faire compiler ce code? Merci pour toute aide ~
Je vois. Et j'ai ajusté le code pour le voir compile:
instance Monad (Either a) where
return = Right
Left a >>= f = Left a
Right x >>= f = f x
Il compile avec succès! Mais ... pour une nouvelle question:
instance Monad (Either a)
Fait «un« a »une monade et j'ai obtenu» return = droite »... comment pourrais-je obtenir« retour = gauche »? J'ai essayé cela mais j'ai échoué:
instance Monad (`Either` a) where
return = Left
Right a >>= f = Right a
Left x >>= f = f x
ou: instance monad ( x -> soit xa)
ne compile pas du tout!
La solution
- Le retour doit avoir le type
forall b. b -> Either a b
, Cependant, la gauche a le typeforall c. a -> Either a c
. Vous voulez probablement ici. fail
devrait avoir le typeforall b. String -> Either a b
, Cependant, la bonne a le typeforall b. b -> Either a b
, donc sib=String
qui faitString -> Either a String
ce qui ne convient pas.>>=
devrait avoir le typeEither a b -> (b -> Either a c) -> Either a c
toutefoisRight x >>= _ = Right x
Renvoie toujours une valeur de typeEither a b
, ne pasEither a c
.Left x >>= f = f x
ne fonctionne pas parce que x a le typea
, maisf
a le typeb -> c
.
Autres conseils
La plupart de la confusion provient du fait que la gauche et la droite sont utilisées à l'envers. Compte tenu uniquement du type de retour, son type de la TypeClass de Monad est le suivant:
return :: (Monad m) => b -> m b
Vous essayez de définir une instance pour m
= Either a
, donc le retour devrait avoir le type:
return :: b -> Either a b
Vous le définissez comme à gauche, qui a le type:
Left :: a -> Either a b
Notez comment le côté gauche du ->
diffère.