質問

I was working through some examples and came across an error with my implementation of bind (>>=) for the Error monad:

data E a = Success a
         | Error String

instance Monad E where
    return a = Success a
    (Success a) >>= f = f a
    e@(Error s) >>= _ = e

 

Error.hs:15:25:
Couldn't match type `a' with `b'
  `a' is a rigid type variable bound by
      the type signature for >>= :: E a -> (a -> E b) -> E b
      at Error.hs:14:5
  `b' is a rigid type variable bound by
      the type signature for >>= :: E a -> (a -> E b) -> E b
      at Error.hs:14:5
Expected type: E b
  Actual type: E a
In the expression: e
In an equation for `>>=': e@(Error s) >>= _ = e
In the instance declaration for `Monad E'

If don't use a named pattern (the @ syntax), everything works:

(Error s) >>= _ = Error s

Why aren't these two forms equivalent? What is going on?

役に立ちましたか?

解決

Let's start by looking at the type of Error:

Error :: String -> E a

That means that for any a type, you can get an E a by using something like Error "foo". However, each specific Error "foo" value has to choose a specific a, and you can't change it afterwards. So Error "foo" :: E Int is not the same as Error "foo" :: E String.

So in your specific example, e is referring to the actual "original" Error s value, of type E a, whereas in the alternative formulation you are constructing a new Error s value, which type inference forces to have type E b.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top