我想复制列表的第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.
有人能告诉我我做错了吗?
答案 0 :(得分:4)
list !! n
返回列表元素,而不是列表。 ++
只能连接列表;您无法使用++
将列表元素添加到列表中。
更正式地说,!!
的类型为:
(!!) :: [a] -> Int -> a
表示它接受a
和Int
的列表,并返回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
超出范围,这不会中断。