我正在处理一些示例,并且遇到错误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
为什么这两种形式不相同?发生了什么事?
答案 0 :(得分:12)
让我们先看一下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
值,而在替代公式中,您构建的是 new Error s
值,类型推断强制使用类型E b
。