【问题标题】:Pattern matching Haskell lists模式匹配 Haskell 列表
【发布时间】:2014-12-10 21:55:37
【问题描述】:

我开始使用the University of Pennsylvania's free online course materials 学习 Haskell。这些是故意放到网上的,所以我想我问这个问题不是在帮助任何人做作业。

我从以下函数中得到了一些编译器错误,我用它来回答第一个作业的一部分,我不知道为什么。我的功能是:

doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther [] = []
doubleEveryOther [x] = [x]
doubleEveryOther [x:y] = [x:(y*2)]
doubleEveryOther [x:y:ys] = [x:y*2:doubleEveryOther ys]

我得到的错误是:

01.hs:18:19:
    Couldn't match expected type ‘Integer’ with actual type ‘[a0]’
    In the pattern: x : y
    In the pattern: [x : y]
    In an equation for ‘doubleEveryOther’:
        doubleEveryOther [x : y] = [x : (y * 2)]

01.hs:18:27:
    Couldn't match expected type ‘Integer’ with actual type ‘[a0]’
    Relevant bindings include
      y :: [a0] (bound at 01.hs:18:21)
      x :: a0 (bound at 01.hs:18:19)
    In the expression: x : (y * 2)
    In the expression: [x : (y * 2)]
    In an equation for ‘doubleEveryOther’:
        doubleEveryOther [x : y] = [x : (y * 2)]

01.hs:19:19:
    Couldn't match expected type ‘Integer’ with actual type ‘[Integer]’
    In the pattern: x : y : ys
    In the pattern: [x : y : ys]
    In an equation for ‘doubleEveryOther’:
        doubleEveryOther [x : y : ys] = [x : y * 2 : doubleEveryOther ys]

01.hs:19:30:
    Couldn't match expected type ‘Integer’ with actual type ‘[Integer]’
    In the expression: x : y * 2 : doubleEveryOther ys
    In the expression: [x : y * 2 : doubleEveryOther ys]
    In an equation for ‘doubleEveryOther’:
        doubleEveryOther [x : y : ys] = [x : y * 2 : doubleEveryOther ys]

谁能帮我理解为什么我的模式不匹配正确的类型?

【问题讨论】:

  • 太累了,无法完整回答,抱歉,但以下内容可能会给您一个想法:[x,y], (x:y:ys)

标签: haskell types


【解决方案1】:

问题很简单:[] 表示元素列表。 : 表示连接一个元素和一个列表。所以[x:ys] 实际上意味着[[x,y1,y2..]] - 注意双括号。因此,在您的情况下,它是Integer 的列表,而不是Integer 的列表。

doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther [] = []
doubleEveryOther [x]= [x]
doubleEveryOther [x,y] = [x, y*2]
doubleEveryOther (x:y:ys) = x : y*2 : doubleEveryOther ys

如果您希望所有 4 个等式都使用相同的语法,则不能使用 [],因为它不允许 ys,因此您必须在任何地方使用 :

doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther [] = []
doubleEveryOther (x:[])= x:[]
doubleEveryOther (x:y:[]) = x : y*2 : []
doubleEveryOther (x:y:ys) = x : y*2 : doubleEveryOther ys

【讨论】:

  • [x:ys] 实际上是 [[x,y1,y2..]]。这不是 100% 准确的。在[x:ys] 模式中,ys 可以为 nil,此时没有y1y2
【解决方案2】:

代码应该是:

doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther [] = []
doubleEveryOther [x] = [x]
doubleEveryOther (x:y:[]) = [x, (y*2)]
doubleEveryOther (x:y:ys) = x: y*2 : doubleEveryOther ys

您不能直接在列表上进行模式匹配,因为列表语法只是语法糖。您必须匹配函数调用(特别是对 (:) 的调用,即 cons 运算符)。这些匹配项需要用括号括起来。

而且您不会将 cons 调用括在括号中。 [1 : 2 : []][[1, 2]] 相同。只是为了让它更清楚一点,在你的代码中你有[x : y*2]xy 都是 Ints。但缺点(:)(:) :: a -> [a] -> [a] 类型。你用两个Ints 调用它,而不是你应该的Int[Int]

【讨论】:

  • [x] 是单例列表的有效模式;它不一定是(x:[])。加里是对的。
  • 谢谢,解决了。您能否详细说明为什么您的最终模式匹配有效,但在倒数第二个匹配中使用 cons 运算符无效?我想确保我真的明白这一点。
  • 你的意思是在等式的右边吗? x: (y*2): doubles ys 有效,因为它将doubles 的结果,将y 放在前面,然后将x 放在前面。第 4 行右边可以表示为x: (y*2): [],直接表达缺点。它需要一个空列表,在 y 上进行 conses,然后在 x 上进行 conses。但是因为我们已经知道了整个列表,所以我们可以使用列表语法糖直接写[x, y*2]。我们不能在最后一行使用列表语法糖,因为我们不知道doubleEveryOther 的结果。
【解决方案3】:

另外,你的第 3 行是第 4 行的一部分,所以

doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther [] = []
doubleEveryOther [x]= [x]
doubleEveryOther (x:y:ys) = x : y*2 : doubleEveryOther ys

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-20
    • 2021-11-18
    • 2017-11-13
    • 2021-05-22
    相关资源
    最近更新 更多