开发者

Why this Either-monad code does not type check?

开发者 https://www.devze.com 2022-12-25 15:51 出处:网络
instance Monad (Either a) where return = Left fail = Right Left x >>= f = f x Right x >>= _ = Right x
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.


  1. return should have type forall b. b -> Either a b, however Left has type forall c. a -> Either a c. You probably want Right here.
  2. fail should have type forall b. String -> Either a b, however Right has type forall b. b -> Either a b, so if b=String that makes String -> Either a String which does not fit.
  3. >>= should have type Either a b -> (b -> Either a c) -> Either a c however Right x >>= _ = Right x always returns a value of type Either a b, not Either a c.
  4. Left x >>= f = f x does not work because x has type a, but f has type b -> c.
0

精彩评论

暂无评论...
验证码 换一张
取 消