5
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, 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.

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!

pf_miles
  • 907
  • 1
  • 8
  • 17

2 Answers2

9

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.

JB.
  • 40,344
  • 12
  • 79
  • 106
  • 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! – pf_miles Apr 07 '10 at 15:45
  • You can't make `Either a` a Monad with `return`=`Left`. A Haskell `Monad` is a typeclass of one parameter (let's take `b`), which matches the `return`'s argument's type. This is incompatible with Haskell's definition of `Either`, which is a typeclass where the last argument is the one to the `Right`. You could only achieve what you want by redefining `Either` with swapped type arguments, as in `data Either a b = Left b | Right a` but then you'd be incompatible with all the standard library's support on `Either` values. – JB. Apr 07 '10 at 16:05
3
  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.
sepp2k
  • 363,768
  • 54
  • 674
  • 675