9

我需要获取列表的第 n 个元素,但不使用!!运算符。我对haskell非常陌生,所以如果您能更详细地回答而不仅仅是一行代码,我将不胜感激。这就是我目前正在尝试的:

nthel:: Int -> [Int] -> Int
nthel n xs = 0
let xsxs = take n xs
nthel n xs = last xsxs

但我得到:解析错误(可能不正确的缩进)

4

4 回答 4

13

这里有很多东西有点不对劲,

nthel :: Int -> [Int] -> Int

在技​​术上是正确的,我们真的想要

nthel :: Int -> [a] -> a

所以我们可以在任何列表上使用它(可选)

nthel n xs = 0

你刚才说的是“不管你付出什么都nthel返回0”。这显然是错误的。

let xsxs = ...

这不是合法的haskell。let ... in ...是表达式,不能用于顶层。

从那里我不确定那应该做什么。

也许这会帮助你走上正确的轨道

nthelem n [] = <???> -- error case, empty list
nthelem 0 xs = head xs
nthelem n xs = <???> -- recursive case

尝试填写<???>您的最佳猜测,我很乐意从那里提供帮助。

或者,您可以使用 Haskell 的“模式匹配”语法。我在这里解释了如何使用列表来做到这一点。

这将我们的上述更改为

nthelem n [] = <???> -- error case, empty list
nthelem 0 (x:xs) = x --bind x to the first element, xs to the rest of the list
nthelem n (x:xs) = <???> -- recursive case

这样做很方便,因为它不需要使用显式headtails。

于 2013-04-12T21:39:54.470 回答
9

我想你的意思是:

nthel n xs = last xsxs
  where xsxs = take n xs

...您可以简化为:

nthel n xs = last (take n xs)
于 2013-04-12T22:23:39.543 回答
1

我认为你应该尽可能避免使用last- 列表是从“前端”使用的,而不是从后面使用。您想要的是摆脱前 n 个元素,然后获取剩余列表的头部(当然,如果其余部分为空,则会出现错误)。您可以直接将其表达为:

nthel n xs = head (drop n xs)

或更短:

nthel n = head . drop n

或者有点疯狂:

nthel = (head .) . drop
于 2013-04-13T10:39:29.927 回答
1

如您所知,列表不是自然索引的,但可以使用通用技巧来克服它。

试试 ghci, zip [0..] "hello", 什么是zip [0,1,2] "hello"or zip [0..10] "hello"
从这个观察开始,我们现在可以很容易地获得一种方法来索引我们的列表。
此外,它很好地说明了懒惰的使用,为您的学习过程提供了很好的提示。

然后基于此并使用模式匹配,我们可以提供一种有效的算法。

  1. 边界案例的管理(空列表、负索引)。
  2. 使用 zipper 将列表替换为索引版本。
  3. 调用辅助函数设计来递归处理我们的索引列表。

现在对于辅助函数,列表不能为空,然后我们可以天真地进行模式匹配,并且,

  • 如果我们的索引等于 n 我们就有赢家
  • 否则,如果我们的下一个元素为空,则结束
  • 否则,使用下一个元素调用辅助函数。

附加说明,因为我们的函数可能会失败(空列表......),使用 Maybe 类型包装我们的结果可能是一件好事。

把这一切放在一起,我们就结束了。

nth :: Int -> [a] -> Maybe a
nth n xs 
    | null xs || n < 0 = Nothing
    | otherwise        = helper n zs 
      where 
        zs = zip [0..] xs 
        helper n ((i,c):zs) 
            | i == n    = Just c
            | null zs   = Nothing
            | otherwise = helper n zs 
于 2013-04-13T15:39:52.283 回答