Haskell在第n个位置插入元素

Jan*_*ski 0 haskell

嗨,我开始学习haskell,但我找不到一个主题。

假设我有一个列表:[1,2,3],我正在尝试编写一个在第n个位置插入元素的函数。任何线索,我该怎么做?

Jak*_*nge 6

您可以构建如下insertAt函数:

insertAt :: a -> Int -> [a] -> [a]
insertAt newElement 0 as = newElement:as
insertAt newElement i (a:as) = a : insertAt newElement (i - 1) as
Run Code Online (Sandbox Code Playgroud)

解决此类问题的一种策略是针对某些边缘情况编写代码,并使用递归直到找到边缘情况。

在代码可能变得更短,更易于编写的意义上,上述镜头包简化了处理数据结构的过程,但以学习额外的库为代价。

这两个示例都强调了有几种方法可以解决您的问题。我建议看一下Data.List模块,以进一步了解典型的列表操作。该drop功能可能是一个良好的开端为您服务。同样,提供的splitAt功能可能是解决您的问题的合适基础。


正如Shersh正确提到的那样,的上述实现存在insertAt一定缺陷:它不检查是否有负面头寸,如果给定一个头寸,则可以继续递归。在无限列表的情况下,这可能特别糟糕。

通过使用防护,我们可以轻松地改进实现:

insertAt :: a -> Int -> [a] -> [a]
insertAt newElement _ [] = [newElement]
insertAt newElement i (a:as)
  | i <= 0 = newElement:a:as
  | otherwise = a : insertAt newElement (i - 1) as
Run Code Online (Sandbox Code Playgroud)

此实现尝试通过在有疑问时立即插入立即执行正确的操作newElement。也可以编写该版本的版本insertAt,而不是在我们的面前抛出错误:

import Data.Monoid ((<>))
import qualified Data.List as List

insertAt :: a -> Int -> [a] -> [a]
insertAt newElement i as
  | null as && i != 0 = error "Cannot insert into empty list other than position 0."
  | null as && i == 0 = [newElement]
  | i >= 0 = let (prefix, suffix) = List.splitAt i
             in prefix <> [i] <> suffix
Run Code Online (Sandbox Code Playgroud)

此版本也List.splitAt为了简洁起见。