Haskell - 从结尾找到第k个元素,而haskell不能匹配模式

时间:2015-04-11 04:59:47

标签: haskell

我试图实现一个从末尾返回k元素的递归函数。

这是我的尝试:

kElementFromEnd :: Int -> [x] -> x

kElementFromEnd _ [] = error "cannot request k item from empty list"
kElementFromEnd k [x]
    | k < 0 = error "k must be non negative"
    | k == 0 = last [x]
    | otherwise = kElementFromEnd (k-1) (init [x])

这是我收到的错误:

*Main> kElementFromEnd 2 [1,2,3]
*** Exception: EX2.hs:(4,1)-(8,54): Non-exhaustive patterns in function kElementFromEnd

我真的不明白为什么haskell无法匹配这种模式。发生了什么事,我不理解?

由于

2 个答案:

答案 0 :(得分:6)

您只匹配空列表([])和单个元素列表([x])。我认为您的意思是替换[x],这是一个与单个元素列表匹配的模式,并将该单个值分配给x,只需xs,一个匹配任何列表的模式还没有匹配。这看起来像

kElementFromEnd :: Int -> [x] -> x
-- This pattern matches the empty list
kElementFromEnd _ [] = error "cannot request k item from empty list"
-- This pattern is just a name, so it matches everything else
-- i.e. non-empty lists
kElementFromEnd k xs
    | k < 0 = error "k must be non negative"
    | k == 0 = last xs
    | otherwise = kElementFromEnd (k-1) (init xs)

它可以作为

> kElementFromEnd 0 [1..5]
5
> kElementFromEnd 4 [1..5]
1
> map (\i -> kElementFromEnd i [1..10]) [0..9]
[10,9,8,7,6,5,4,3,2,1]

答案 1 :(得分:4)

写这样的功能绝对是一个很好的练习。首先,GHC可以帮助您捕获这样的错误。特别是-fwarn-incomplete-patterns如果你的模式不完整会发出警告,防止出现令人讨厌的运行时错误。使用-Werror,您也可以将其设为错误,以确保您不会错过警告。使用-Wall -Werror进行编译以消除所有可能的警告并不是一种不好的做法。

其次,为了让练习更难:由于init O(n),你的函数实现是 O(kn)(或者更精确 O(min(k,n)n)。对于非常小的 k 它并不重要,但如果k≈n ,您将获得二次性能。所以我建议您尝试找到一个实现

  • O(n)(独立于 k ),
  • 适用于大型懒惰列表;也就是说,以这样一种方式遍历列表:如果没有其他东西将列表保存在内存中,则列表开头的元素将被GC连续丢弃;特别是,空间复杂度应该与 n 无关。

扰流:

  

kElementFromEnd k xs = last $ zipWith const xs (drop k xs)

此外,优雅地失败通常会更好,因为调用error意味着您的程序立即存在。所以另一个改进是制作类型签名

kElementFromEnd :: Int -> [x] -> Maybe x