Haskell let 表达式中出现奇怪的类型错误——问题出在哪里?
今天我在 Haskell 中遇到了一件令人沮丧的事情。
发生的事情是这样的:
- 我在 ghci 中编写了一个函数,并给了它一个类型签名
- ghci 抱怨了该类型
- 我删除了类型签名
- ghci 接受了该函数
- 我检查了推断类型
- 推断类型与我尝试赋予它的类型完全相同
- 我很苦恼地
- 发现我可以在任何let表达式中重现这个问题,
- 咬牙切齿;决定咨询 SO 的专家
尝试使用类型签名定义函数:
Prelude Control.Monad> let myFilterM f m = do {x <- m; guard (f x); return x} :: (MonadPlus m) => (b -> Bool) -> m b -> m b
<interactive>:1:20:
Inferred type is less polymorphic than expected
Quantified type variable `b' is mentioned in the environment:
m :: (b -> Bool) -> m b -> m b (bound at <interactive>:1:16)
f :: (m b -> m b) -> Bool (bound at <interactive>:1:14)
Quantified type variable `m' is mentioned in the environment:
m :: (b -> Bool) -> m b -> m b (bound at <interactive>:1:16)
f :: (m b -> m b) -> Bool (bound at <interactive>:1:14)
In the expression:
do { x <- m;
guard (f x);
return x } ::
(MonadPlus m) => (b -> Bool) -> m b -> m b
In the definition of `myFilterM':
myFilterM f m
= do { x <- m;
guard (f x);
return x } ::
(MonadPlus m) => (b -> Bool) -> m b -> m b
定义没有类型签名的函数,检查推断的类型:
Prelude Control.Monad> let myFilterM f m = do {x <- m; guard (f x); return x}
Prelude Control.Monad> :t myFilterM
myFilterM :: (MonadPlus m) => (b -> Bool) -> m b -> m b
使用功能非常好 - 它工作正常:
Prelude Control.Monad> myFilterM (>3) (Just 4)
Just 4
Prelude Control.Monad> myFilterM (>3) (Just 3)
Nothing
我对正在发生的事情的最佳猜测:
当存在 do 块时,类型注释在某种程度上不能很好地与 let 表达式配合使用。
奖励积分:
标准 Haskell 发行版中有一个函数可以做到这一点吗?我很惊讶 filterM
做了一些非常不同的事情。
I came across a frustrating something in Haskell today.
Here's what happened:
- I wrote a function in ghci and gave it a type signature
- ghci complained about the type
- I removed the type signature
- ghci accepted the function
- I checked the inferred type
- the inferred type was exactly the same as the type I tried to give it
- I was very distressed
- I discovered that I could reproduce the problem in any let-expression
- Gnashing of teeth; decided to consult with the experts at SO
Attempt to define the function with a type signature:
Prelude Control.Monad> let myFilterM f m = do {x <- m; guard (f x); return x} :: (MonadPlus m) => (b -> Bool) -> m b -> m b
<interactive>:1:20:
Inferred type is less polymorphic than expected
Quantified type variable `b' is mentioned in the environment:
m :: (b -> Bool) -> m b -> m b (bound at <interactive>:1:16)
f :: (m b -> m b) -> Bool (bound at <interactive>:1:14)
Quantified type variable `m' is mentioned in the environment:
m :: (b -> Bool) -> m b -> m b (bound at <interactive>:1:16)
f :: (m b -> m b) -> Bool (bound at <interactive>:1:14)
In the expression:
do { x <- m;
guard (f x);
return x } ::
(MonadPlus m) => (b -> Bool) -> m b -> m b
In the definition of `myFilterM':
myFilterM f m
= do { x <- m;
guard (f x);
return x } ::
(MonadPlus m) => (b -> Bool) -> m b -> m b
Defined the function without a type signature, checked the inferred type:
Prelude Control.Monad> let myFilterM f m = do {x <- m; guard (f x); return x}
Prelude Control.Monad> :t myFilterM
myFilterM :: (MonadPlus m) => (b -> Bool) -> m b -> m b
Used the function for great good -- it worked properly:
Prelude Control.Monad> myFilterM (>3) (Just 4)
Just 4
Prelude Control.Monad> myFilterM (>3) (Just 3)
Nothing
My best guess as to what is going on:
type annotations somehow don't work well with let-expressions, when there's a do-block.
For bonus points:
is there a function in the standard Haskell distribution that does this? I was surprised that filterM
does something very different.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
问题在于类型运算符 (
::
) 的优先级。您试图描述myFilterM
的类型,但您实际上在做的是这样的:(插入反斜杠只是为了便于阅读,而不是合法的 ghci 语法)
您看到问题了吗?对于简单的问题,我遇到了同样的问题,例如
解决方案是将类型签名附加到正确的元素:
对于奖励积分,您需要
mfilter
(hoogle 是你的朋友)。The problem is the precedence of the type operator (
::
). You're trying to describe the type ofmyFilterM
but what you're actually doing is this:(backslashes inserted for readability only, not legit ghci syntax)
Do you see the issue? I get the same problem for something simple like
The solution is to attach the type signature to the proper element:
And for bonus points, you want
mfilter
(hoogle is your friend).这可能只是类型注释语法和绑定优先级的问题。如果您将示例写为,
那么 GHCi 会给您一个高五并让您继续前进。
This is likely just an issue of type annotation syntax and binding precendence. If you write your example as,
then GHCi will give you a high-five and send you on your way.
我不知道你使用哪种编译器,但在我的平台(GHC 7.0.3)上,我得到一个简单的类型不匹配:
我想问题在于
::
确实没有达到论据。这个小的变化(注意单独的类型声明)运行没有问题。这可能与 GHC 7 中新的类型检查器有关。
I don't know what kind of compiler you use, but on my platform (GHC 7.0.3) I get a simple type mismatch:
I guess the problem lies in the fact, that the
::
does not reaches the argument. This small variation (note the separate type declaration)runs without problems. It may be related to the new type-checker in GHC 7.