¿Por qué este código de una mónada no escribe?
Pregunta
instance Monad (Either a) where
return = Left
fail = Right
Left x >>= f = f x
Right x >>= _ = Right x
Este código se frag en 'baby.hs' causó el horrible error de compilación:
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.
¿Por qué sucede esto? ¿Y cómo podría hacer que este código compile? Gracias por cualquier ayuda ~
veo. y ajusté el código para verlo compilación:
instance Monad (Either a) where
return = Right
Left a >>= f = Left a
Right x >>= f = f x
¡Se compila con éxito! Pero ... para otra pregunta más:
instance Monad (Either a)
Hace que 'una' una mónada y obtuve 'return = right' ... ¿cómo podría obtener 'return = izquierda'? He intentado esto pero fallé:
instance Monad (`Either` a) where
return = Left
Right a >>= f = Right a
Left x >>= f = f x
o: instancia monad ( x -> o xa)
¡No se compila en absoluto!
Solución
- El regreso debe tener tipo
forall b. b -> Either a b
, sin embargo, la izquierda tiene tipoforall c. a -> Either a c
. Probablemente quieras aquí. fail
debería tener tipoforall b. String -> Either a b
, sin embargo, el derecho tiene el tipoforall b. b -> Either a b
, Así que sib=String
lo que haceString -> Either a String
que no encaja.>>=
debería tener tipoEither a b -> (b -> Either a c) -> Either a c
sin embargoRight x >>= _ = Right x
siempre devuelve un valor de tipoEither a b
, noEither a c
.Left x >>= f = f x
no funciona porque X tiene tipoa
, perof
tiene tipob -> c
.
Otros consejos
La mayoría de la confusión proviene del hecho de que izquierda y derecha se usan hacia atrás. Teniendo en cuenta solo el tipo de retorno, su tipo de typeclass de mónadas es el siguiente:
return :: (Monad m) => b -> m b
Estás tratando de definir una instancia para m
= Either a
, así que la devolución debe tener tipo:
return :: b -> Either a b
Lo estás definiendo como a la izquierda, que tiene tipo:
Left :: a -> Either a b
Tenga en cuenta cómo el lado izquierdo del ->
difiere.