[英]Anything wrong with the type declaration?
I am reading the book "Programming in Haskell". 我正在阅读“Haskell编程”一书。 One exercise asks me to define map f
using an higher-order function. 一个练习要求我使用高阶函数定义map f
。 I choose to define map (+1)
like the following: 我选择定义map (+1)
,如下所示:
unfold p h t x | p x = []
| otherwise = h x : unfold p h t (t x)
-- equivalent to `map (+1)`
mapinc = unfold (==[]) ((+1).head) tail
(Taken straight from the exercise question) The function unfold pht
produces the empty list if the predicate p
is true of the argument value, and otherwise produces a non-empty list by applying the function h
to this value to give the head, and the function t
to generate another argument that is recursively processed in the same way to produce the tail of the list. (直接来自练习题)如果谓词p
为参数值为true,则函数unfold pht
生成空列表,否则通过将函数h
应用于此值来生成非空列表以给出头部,并且function t
生成另一个参数,以相同的方式递归处理以生成列表的尾部。
I have checked my implementation of mapinc
and it looks fine: 我检查了mapinc
实现,看起来很好:
*Main> mapinc [1,2,3]
[2,3,4]
However, after I add the type declaration: 但是,在我添加类型声明后:
mapinc :: Num a => [a] -> [a]
mapinc = unfold (==[]) ((+1).head) tail
Then reload the script in WinGHCi, it gives the following error: 然后在WinGHCi中重新加载脚本,它会出现以下错误:
• Could not deduce (Eq a) arising from a use of ‘==’
from the context: Num a
bound by the type signature for:
mapinc :: forall a. Num a => [a] -> [a]
at D:\7a.hs:4:1-29
Possible fix:
add (Eq a) to the context of
the type signature for:
mapinc :: forall a. Num a => [a] -> [a]
• In the first argument of ‘unfold’, namely ‘(== [])’
In the expression: unfold (== []) ((+ 1) . head) tail
In an equation for ‘mapinc’:
mapinc = unfold (== []) ((+ 1) . head) tail
|
5 | mapinc = unfold (==[]) ((+1).head) tail | ^^^^
Any clue why it happens? 任何线索为什么会发生?
Your signature is too broad . 你的签名太宽泛了 。 The predicate you have written is == []
. 你写的谓词是== []
。 Haskell can only check if two lists are equal, if the elements of the list can be checked as well. Haskell只能检查两个列表是否相等,是否也可以检查列表的元素 。 In the source code we see something like: 在源代码中我们看到类似于:
instance Eq a => Eq [a] where
...
Yes, here we will never check the equality of two items, since we check with the empty list, but the compiler of course does not know that: it simply sees that in order to check whether two lists are equal, we need to be able to check if elements are equal. 是的,在这里我们永远不会检查两个项目的相等性,因为我们检查空列表,但编译器当然不知道:它只是看到为了检查两个列表是否相等,我们需要能够检查元素是否相等。
The Num
typeclass does not imply that the type is also an Eq
type. 在Num
类型类并不意味着该类型也是一个Eq
类型。 We can do two things here: 我们可以在这做两件事:
add the Eq
type constraint to the signature: 将Eq
类型约束添加到签名:
mapinc :: (Eq a, Num a ) => [a] -> [a] mapinc = unfold (==[]) ((+1).head) tail
more elegant: do not rely on the fact that we need to be able to compare elements, but use null :: [a] -> Bool
instead (a function that checks if the list is empty): 更优雅:不要依赖于我们需要能够比较元素的事实,而是使用null :: [a] -> Bool
(一个检查列表是否为空的函数):
mapinc :: Num a => [a] -> [a] mapinc = unfold null ((+1).head) tail
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.