Haskell在某个位置重复元素

时间:2013-02-25 23:20:44

标签: list haskell list-comprehension

我想复制列表的第n个元素,我对haskell的了解非常有限。 我尝试将列表拆分为两部分,然后获取第一部分的最后一个元素,并将它粘贴在这些部分之间:

dupl n (x:xs) = (take n (x:xs)) ++ ( (x:xs) !! n) ++ (drop n (x:xs))

但我总是得到错误:

Prelude> :l f.hs
[1 of 1] Compiling Main             ( f.hs, interpreted )

f.hs:5:39:
   Occurs check: cannot construct the infinite type: a0 = [a0]
   In the first argument of `(:)', namely `x'
   In the first argument of `(!!)', namely `(x : xs)'
   In the first argument of `(++)', namely `((x : xs) !! n)'
Failed, modules loaded: none.

有人能告诉我我做错了吗?

2 个答案:

答案 0 :(得分:4)

list !! n返回列表元素,而不是列表。 ++只能连接列表;您无法使用++将列表元素添加到列表中。

更正式地说,!!的类型为:

(!!) :: [a] -> Int -> a

表示它接受aInt的列表,并返回a。另一方面,++有一种类型:

(++) :: [a] -> [a] -> [a]

表示它接受两个a列表并返回a s的新列表。因此,您可以看到++接受列表,但!!不会返回列表,因此您不允许将它们链接在一起。


我们如何解决这个问题?你需要将元素list !! n放入一个列表中,以便将它连接到其他两个列表,而不需要类型检查器抛出一个混合物。

这应该可以解决问题:

dupl n l = (take n l) ++ [l !! n] ++ (drop n l)

等效地,将所选元素添加到右侧列表中,并将其连接到原始列表的另一半:

dupl n l = (take n l) ++ ((l !! n):(drop n l))

警告lector :与@ Marimuthu的建议不同,上述两个函数都会引发异常,如果n是一个越界索引。例外来自!!

答案 1 :(得分:1)

您还可以使用splitAt

dupl n xs = first ++ take 1 rest ++ rest where (first, rest) = splitAt (n - 1) xs 

如果n超出范围,这不会中断。