Haskell列表索引超出范围

时间:2015-02-10 09:59:51

标签: haskell

如何修改以下功能,使列表短于搜索索引的情况将导致错误。

elementAt::Int -> [Int] -> Int
elementAt = Data.Foldable.foldl (\x y -> if x == 0 then y else x-1)

1是第一个元素的索引

1 个答案:

答案 0 :(得分:6)

使用折叠来查找列表中的第n个元素是一种非常困难的方法。我想使用显式递归向您展示一种更简单的方法:

你必须以不同的方式看待这个问题:

  1. 我的基本情况是什么?
  2. 递归调用应该如何?
  3. (可选)错误怎么办?
  4. 方法的类型签名是:

    elementAt :: Int -> [Int] -> Int
    

    只关注第一点,我们知道如果索引是0,我们想要返回该元素:

    elementAt 1 (x:_) = x
    

    现在如果我们的数字大于1怎么办?在这种情况下,我们希望减少索引结束测试下一项的谓词:

    elementAt n (x:xs) = elementAt (n-1) xs
    

    现在我们差不多完成了!如果我们想要在找不到指定位置的元素时抛出错误,我们只需使用error

    elementAt _ _ = error "Element not found!"
    

    但这不是惯用的Haskell方式的工作方式。一种可能的解决方案是使用Maybe来包装结果。为此,我们必须稍微更改类型签名:

    elementAt :: Int -> [Int] -> Maybe Int
    

    现在该函数能够返回Just指定位置的元素(如果存在),否则Nothing

    elementAt 1 (x:_)  = Just x
    elementAt n (x:xs) = elementAt (n-1) xs
    elementAt _ _      = Nothing
    

    为了完整起见,这里有一种可能的方法来实现这个目的:

    elementAt n = foldl (\acc x -> if fst x == n then snd x else acc) n . zip [1..n]