我正在研究一些示例,并在为 Error 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
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'

如果不使用命名模式(@ 语法),一切正常:
(Error s) >>= _ = Error s

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

最佳答案

让我们先看看 Error 的类型:

Error :: String -> E a

这意味着对于任何 a 类型,您都可以通过使用类似 E a 的东西来获取 Error "foo" 。但是,每个特定的 Error "foo" 值都必须选择一个特定的 a ,并且之后无法更改它。所以 Error "foo" :: E IntError "foo" :: E String 不同。

因此,在您的具体示例中, e 指的是 Error s 类型的实际“原始” E a 值,而在替代公式中,您正在构建一个新的 Error s 值,该类型推断强制具有 E b 类型。

关于haskell - 命名模式和类型推断?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23597888/

10-16 19:19