我正在研究一些示例,并在为 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 Int
与 Error "foo" :: E String
不同。因此,在您的具体示例中,
e
指的是 Error s
类型的实际“原始” E a
值,而在替代公式中,您正在构建一个新的 Error s
值,该类型推断强制具有 E b
类型。关于haskell - 命名模式和类型推断?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23597888/