Why this Either-monad code does not type check?
instance Monad (Either a) where
return = Left
fail = Right
Left x >>= f = f x
Right x >>= _ = Right x
this code frag in 'baby.hs' caused the horrible compilation error:
Prelude> :l baby
[1 of 1] Compiling Main ( baby.hs, in开发者_JAVA技巧terpreted )
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.
why this happen? and how could I make this code compile ? thanks for any help~
i see. and i adjusted the code to see it compiles:
instance Monad (Either a) where
return = Right
Left a >>= f = Left a
Right x >>= f = f x
it compiles successfully! but...for a further more question:
instance Monad (Either a)
makes 'Either a' a monad and i got 'return = Right'...how could i get 'return = Left'? i've tried this but failed:
instance Monad (`Either` a) where
return = Left
Right a >>= f = Right a
Left x >>= f = f x
or: instance Monad (\x -> Either x a)
doesn't compile at all!
Most of the confusion stems from the fact Left and Right are used backwards. Considering only the type for return, its type from the Monad typeclass is as follows:
return :: (Monad m) => b -> m b
You're trying to define an instance for m
= Either a
, so return should have type:
return :: b -> Either a b
You're defining it as Left, which has type:
Left :: a -> Either a b
Note how the left hand side of the ->
differs.
- return should have type
forall b. b -> Either a b
, however Left has typeforall c. a -> Either a c
. You probably want Right here. fail
should have typeforall b. String -> Either a b
, however Right has typeforall b. b -> Either a b
, so ifb=String
that makesString -> Either a String
which does not fit.>>=
should have typeEither a b -> (b -> Either a c) -> Either a c
howeverRight x >>= _ = Right x
always returns a value of typeEither a b
, notEither a c
.Left x >>= f = f x
does not work because x has typea
, butf
has typeb -> c
.
精彩评论