3

我想复制列表的第 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.

有人可以告诉我我做错了什么吗?

4

3 回答 3

4

list !! n返回一个列表元素,而不是一个列表。++只能连接列表;您不能将列表元素添加到带有++.

更正式地说,!!有一种类型:

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

这意味着它接受as 和 an的列表Int,并返回 an a++,另一方面,具有以下类型:

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

这意味着它接受两个as 列表并返回一个新的as 列表。所以你可以看到它++接受列表,但!!不返回列表,所以你不能像那样将它们链接在一起。


我们如何解决这个问题?您需要将元素list !! n放入一个列表中,以便将其连接到其他两个列表,而不会让类型检查器产生混乱。

这应该可以解决问题:

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

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

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

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

于 2013-02-25T23:26:48.537 回答
2

如果您选择了错误的索引,请注意购买者,但是-</p>

dupN n xs = let (first, x:rest) = splitAt (n-1) xs in first ++ x:x:rest
于 2013-02-26T00:55:21.757 回答
1

您还可以使用splitAt

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

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

于 2013-02-26T00:06:22.433 回答