Haskell let-expression 中出现奇怪的类型错误——问题是啥?
Posted
技术标签:
【中文标题】Haskell let-expression 中出现奇怪的类型错误——问题是啥?【英文标题】:Strange type error in Haskell let-expression -- what's the issue?Haskell let-expression 中出现奇怪的类型错误——问题是什么? 【发布时间】:2011-12-01 13:16:27 【问题描述】:我今天在 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
做了一些非常不同的事情。
【问题讨论】:
类型注释适用于定义的RHS,而不是myFilterM
,所以你应该说:: (MonadPlus m) => m b
。这就是为什么您的错误消息中m
和f
的类型如此奇怪的原因。但我仍然收到“推断类型的多态性低于预期”错误消息(尽管类型更合理),我不知道是什么原因造成的。
@dave4420 你也使用 GHC 6.* 吗?他们在 GHC 7 中编写了一个新的类型推理引擎;也许这是一个错误。
@FUZxxl 那是 GHC 6.12.1。我刚刚用 GHC 7.0.3 尝试过,我收到两条错误消息而不是一条,它们都没有提到多态性。可能是 GHC 7 拒绝推断 myFilterM
的参数类型。
【参考方案1】:
问题在于类型运算符的优先级(::
)。您试图描述 myFilterM
的类型,但您实际上在做的是:
ghci> let myFilterM f m = (\
do x <- m; guard (f x); return x \
:: \
(MonadPlus m) => (b -> Bool) -> m b -> m b)\
)
(插入反斜杠只是为了便于阅读,不是合法的 ghci 语法)
你看到问题了吗?对于像
这样简单的事情,我也遇到了同样的问题ghci> let f x = x + 1 :: (Int -> Int)
<interactive>:1:15:
No instance for (Num (Int -> Int))
arising from the literal `1'
Possible fix: add an instance declaration for (Num (Int -> Int))
In the second argument of `(+)', namely `1'
In the expression: x + 1 :: Int -> Int
In an equation for `f': f x = x + 1 :: Int -> Int
解决方案是将类型签名附加到适当的元素:
ghci> let f :: Int -> Int ; f x = x + 1
ghci> let myFilterM :: (MonadPlus m) => (b -> Bool) -> m b -> m b; myFilterM f m = do x <- m; guard (f x); return x
对于奖励积分,您需要mfilter
(hoogle is your friend)。
【讨论】:
谢谢!我不敢相信我以前在使用 ghci 时从未遇到过这种情况。【参考方案2】:这可能只是类型注释语法和绑定优先级的问题。如果你把你的例子写成,
let myFilterM :: (MonadPlus m) => (b -> Bool) -> m b -> m b; myFilterM f m = do x <- m; guard (f x); return x
然后 GHCi 会给你一个高五并送你上路。
【讨论】:
【参考方案3】:我不知道您使用哪种编译器,但在我的平台 (GHC 7.0.3) 上,我得到一个简单的类型不匹配:
$ ghci
GHCi, version 7.0.3: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package ffi-1.0 ... linking ... done.
Prelude> :m +Control.Monad
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:30:
Could not deduce (t1 ~ ((b1 -> Bool) -> m1 b1 -> m1 b1))
from the context (MonadPlus m)
bound by the inferred type of
myFilterM :: MonadPlus m => t -> t1 -> (b -> Bool) -> m b -> m b
at <interactive>:1:5-100
or from (MonadPlus m1)
bound by an expression type signature:
MonadPlus m1 => (b1 -> Bool) -> m1 b1 -> m1 b1
at <interactive>:1:21-100
`t1' is a rigid type variable bound by
the inferred type of
myFilterM :: MonadPlus m => t -> t1 -> (b -> Bool) -> m b -> m b
at <interactive>:1:5
In a stmt of a 'do' expression: x <- m
In the expression:
do x <- m;
guard (f x);
return x ::
MonadPlus m => (b -> Bool) -> m b -> m b
In an equation for `myFilterM':
myFilterM f m
= do x <- m;
guard (f x);
return x ::
MonadPlus m => (b -> Bool) -> m b -> m b
<interactive>:1:40:
Could not deduce (t ~ ((m1 b1 -> m1 b1) -> Bool))
from the context (MonadPlus m)
bound by the inferred type of
myFilterM :: MonadPlus m => t -> t1 -> (b -> Bool) -> m b -> m b
at <interactive>:1:5-100
or from (MonadPlus m1)
bound by an expression type signature:
MonadPlus m1 => (b1 -> Bool) -> m1 b1 -> m1 b1
at <interactive>:1:21-100
`t' is a rigid type variable bound by
the inferred type of
myFilterM :: MonadPlus m => t -> t1 -> (b -> Bool) -> m b -> m b
at <interactive>:1:5
The function `f' is applied to one argument,
but its type `t' has none
In the first argument of `guard', namely `(f x)'
In a stmt of a 'do' expression: guard (f x)
Prelude Control.Monad>
我想问题在于::
没有达到参数。这个小变化(注意单独的类型声明)
let myFilterM f m = do x <- m; guard (f x); return x; myFilterM :: (MonadPlus m) => (b -> Bool) -> m b -> m b
运行没有问题。它可能与 GHC 7 中的新类型检查器有关。
【讨论】:
以上是关于Haskell let-expression 中出现奇怪的类型错误——问题是啥?的主要内容,如果未能解决你的问题,请参考以下文章
在反序列化过程中出现下一个异常:“源数据中的无效字段:0”。如何找出源代码中的原因/错误位置?
禁欲28天!一宅男居然肝出如此详细Web安全学习笔记,学妹看完直接抽搐了!(持续中出)
我在MAX做好的人物骨骼动画导入UNITY 中出问题,人物模型乱七八糟,怎么回事呢?