命名模式和类型推断?

Joh*_*man 4 haskell

我正在研究一些示例,并且遇到了错误monad的bind(>> =)实现错误:

data E a = Success a
         | Error String

instance Monad E where
    return a = Success a
    (Success a) >>= f = f a
    e@(Error s) >>= _ = e
Run Code Online (Sandbox Code Playgroud)

 

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'
Run Code Online (Sandbox Code Playgroud)

如果不使用命名模式(@语法),一切都有效:

(Error s) >>= _ = Error s
Run Code Online (Sandbox Code Playgroud)

为什么这两种形式不相同?到底是怎么回事?

GS *_*ica 12

让我们从查看类型开始Error:

Error :: String -> E a
Run Code Online (Sandbox Code Playgroud)

这意味着对于任何a类型,你都可以E a使用类似的东西Error "foo".但是,每个特定Error "foo"值都必须选择一个特定的值a,然后您无法更改它.所以Error "foo" :: E Int不一样Error "foo" :: E String.

因此,在您的具体示例中,e指的Error s是类型的实际"原始" 值,E a而在替代公式中,您正在构造一个 Error s值,类型推断力类型E b.