【问题标题】:Anything wrong with the type declaration?类型声明有什么问题吗?
【发布时间】:2017-11-30 18:33:17
【问题描述】:

我正在阅读“Haskell 编程”一书。一个练习要求我使用高阶函数定义map f。我选择像下面这样定义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

(直接取自练习题)如果谓词p 对参数值为真,则函数unfold p h t 生成空列表,否则通过将函数h 应用于此生成非空列表value 给出头部,函数t 生成另一个参数,该参数以相同的方式递归处理以产生列表的尾部。

我检查了mapinc 的实现,看起来不错:

*Main> mapinc [1,2,3]
[2,3,4]

但是,在我添加类型声明之后:

mapinc :: Num a => [a] -> [a]
mapinc = unfold (==[]) ((+1).head) tail

然后在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   |                  ^^^^

知道为什么会这样吗?

【问题讨论】:

    标签: haskell higher-order-functions


    【解决方案1】:

    您的签名过于宽泛。你写的谓词是== []。 Haskell 只能检查两个列表是否相等,如果列表的 元素 也可以检查。在源代码中,我们看到如下内容:

    instance Eq a => Eq [a] where
        ...

    是的,这里我们永远不会检查两个项目是否相等,因为我们检查的是空列表,但是编译器当然不知道:它只是看到为了检查两个列表是否相等,我们需要能够检查元素是否相等。

    Num 类型类确实暗示该类型也是Eq 类型。我们可以在这里做两件事:

    1. Eq 类型约束添加到签名中:

      mapinc :: (Eq a, Num a) => [a] -> [a]
      mapinc = unfold (==[]) ((+1).head) tail
    2. 更优雅:不要依赖于我们需要能够比较元素这一事实,而是使用null :: [a] -> Bool(一个检查列表是否为空的函数):

      mapinc :: Num a => [a] -> [a]
      mapinc = unfold null ((+1).head) tail

    【讨论】:

      猜你喜欢
      • 2012-04-04
      • 1970-01-01
      • 2020-05-12
      • 1970-01-01
      • 2012-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-03
      相关资源
      最近更新 更多