2013-02-25 40 views
3

我想複製列表的第n個元素,並且我對haskell的知識非常有限。 我試圖分裂名單兩個部分,然後讓第一部分的最後一個元素,只是這些部件之間粘貼: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

list !! n返回列表元素,不是列表。 ++只能級聯列表;您不能將列表元素添加到列表++

說得更加正式,!!的類型爲:

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

這意味着它接受的a S和一個Int列表,並返回一個a++,在另一方面,有一個類型:

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

這意味着它接受的a的兩個列表,並返回a個新的列表。所以你可以看到++接受列表,但!!不返回列表,所以你不能像這樣鏈接它們。


我們該如何解決?您需要將元素list !! n放入列表中,以便將它連接到其他兩個列表,而不會使類型檢查器發出窘迫。

這應該做的伎倆:

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

等價地,所選擇的元素添加到右側的列表,並連接,爲原始列表中的另一半:

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

警告講師:上述兩個函數,不像@Marimut胡的建議,如果n是一個超出界限的指數,將會引發異常。例外來自!!

1

您還可以使用splitAt

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

如果n是出界的這不會打破。

如果你選擇一個壞指數
2

買者自負,但是 -

dupN n xs = let (first, x:rest) = splitAt (n-1) xs in first ++ x:x:rest 
+1

這是最漂亮的一個。我想,在第一個++ [x,x] ++休息中我會更好。 – luqui 2013-02-26 01:12:14

+0

謝謝!我也很喜歡你的建議。 – 2013-02-26 13:16:14