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



做99-Haskell问题的第三个(我目前正在尝试学习语言)我试图将模式匹配和递归合并到我的函数中,现在看起来像这样:

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;如果是,则返回最后一个elemen;如果没有,则在列表末尾切掉一个元素,然后执行递归。

注意:我知道这是一个非常糟糕的算法,但是我已经为自己设定了编写该函数的挑战,包括递归和模式匹配。我也尽量不使用!!运算符,但这对我来说很好,因为它真正做的唯一事情(或者应该在编译时应该做的)是将单元素列表转换为该元素。

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]++ []

运行时应该选择哪一个?

大概,您正在尝试匹配列表的头部和尾部。让我们逐步完成它:

myElementAt (x:_) 0 = x

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

然后你可以有

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

这意味着如果前面的模式不匹配,则忽略头部,并取尾部的i - 1元素。

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

因此,请尝试以下操作:

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

你的代码中还有更多问题,但至少这解决了你的第一个问题。

在标准的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但我认为你不需要它,特别是你还在学习。

相关内容

  • 没有找到相关文章

最新更新