Haskell:模式x ++ xs中的解析错误

时间:2017-05-29 11:56:59

标签: haskell pattern-matching parse-error

执行third of the 99-Haskell problems(我目前正在尝试学习该语言)我尝试将模式匹配以及递归合并到我的函数中,现在看起来像这样:

myElementAt :: [a] -> Int -> a
myElementAt (x ++ xs) i =
  if length (x ++ xs) == i && length xs == 1 then xs!!0
  else myElementAt x i

这给了我Parse error in pattern: x ++ xs。问题:

  1. 为什么这会给我一个解析错误?是因为Haskell不知道在哪里削减我的名单(这是我最好的猜测)?
  2. 我怎样才能重构我的功能以使其有效?算法的想法是检查列表的长度是否为指定的inde;如果是,则返回最后一个元素;如果没有删除列表末尾的一个元素,然后进行递归。
  3. 注意:我知道这是一个非常糟糕的算法,但我自己设定了编写该函数的挑战,包括递归和模式匹配。我也尝试过不使用!!运算符,但这对我来说很好,因为它真正做的唯一事情(或者如果编译它应该这样做)是将单元素列表转换为该元素。

4 个答案:

答案 0 :(得分:7)

Haskell有两种不同的价值级实体:变量(这也包括函数,中缀运算符,如++等)和构造函数。两者都可以在表达式中使用,但只有构造函数也可以用在模式中。

在任何一种情况下,很容易判断您是否正在处理变量或构造函数:构造函数始终以大写字母开头(例如NothingTrueStateT)或者,如果它是中缀,则带冒号(::+)。其他一切都是变数。从根本上说,不同之处在于构造函数始终是预定义集合中唯一的,可立即匹配的值(即data定义的替代值),而变量只能具有任何值 ,并且通常它原则上不可能唯一地区分不同的变量,特别是如果它们具有函数类型。

你的实际上就是一个很好的例子:为了使模式匹配x ++ xs有意义,必须有一种独特的方式,其中输入列表可以写入表格x ++ xs。好吧,但是,对于[0,1,2,3]来说,有多种不同的方法可以做到这一点:

[] ++[0,1,2,3]
[0] ++ [1,2,3]
[0,1] ++ [2,3]
[0,1,2] ++ [3]
[0,1,2,3]++ []

运行时应该选择哪一个?

答案 1 :(得分:1)

据推测,您正试图匹配列表的头尾部分。让我们一步一步:

myElementAt (x:_) 0 = x

这意味着如果头部为x,则尾部为某物,索引为0,返回头部。请注意,您的x ++ x是两个列表的串联,而不是头部和尾部。

然后你可以

myElementAt(_:tl) i = myElementAt tl (i - 1)

表示如果前一个模式不匹配,则忽略头部,并采用尾部的 i - 1 元素。

答案 2 :(得分:0)

在模式中,您只能使用:[]等构造函数。追加运算符(++)是非构造函数。

所以,试试类似:

myElementAt :: [a] -> Int -> a
myElementAt (x:xs) i = ...

您的代码中存在更多问题,但至少这可以解决您的第一个问题。

答案 3 :(得分:0)

在标准的Haskell模式中匹配如下:

f :: Int -> Int
f (g n 1) = n

g :: Int -> Int -> Int
g a b = a+b

是非法的,因为模式中不允许函数调用,您的情况只是一种特殊情况,因为运算符++只是一个函数。

要对列表进行模式匹配,您可以这样做:

myElementAt :: [a] -> Int -> a
myElementAt (x:xs) i = // result

但在这种情况下,x的类型为a而不是[a],它是列表的头部,xs是它的尾部,您需要更改你的函数实现是为了适应这个事实,这个函数也会因空列表[]而失败。然而,这是模式匹配aginst列表的惯用haskell方式。

我应该提一下,当我说“非法”时,我的意思是标准的Haskell,有GHC扩展提供类似的东西,它被称为ViewPatterns但我认为你不需要它特别是你'还在学习。