Reputation: 1891
I want to duplicate the n-th elemnt of a list and my knowledge of haskell is very limited. I tried splitting the list in two parts, then getting the last element of the first part and just pasting it between those parts:
dupl n (x:xs) = (take n (x:xs)) ++ ( (x:xs) !! n) ++ (drop n (x:xs))
But I always get the error:
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.
Could someone tell me what I am doing wrong?
Upvotes: 3
Views: 704
Reputation: 44634
list !! n
returns a list element, not a list. ++
can only concatenate lists; you can't add a list element to a list with ++
.
To put it more formally, !!
has a type of:
(!!) :: [a] -> Int -> a
which means that it accepts a list of a
s and an Int
, and returns an a
. ++
, on the other hand, has a type of:
(++) :: [a] -> [a] -> [a]
which means that it accepts two lists of a
s and returns a new list of a
s. So you can see that ++
accepts lists, but !!
doesn't return lists, so you're not allowed to chain them together like that.
How do we fix this? You need to put the element list !! n
into a list, in order to concatenate it to the other two lists without the type checker throwing a hissy fit.
This should do the trick:
dupl n l = (take n l) ++ [l !! n] ++ (drop n l)
Equivalently, add the chosen element to the right-hand list, and concatenate that to the other half of the original list:
dupl n l = (take n l) ++ ((l !! n):(drop n l))
Caveat lector: both of the above functions, unlike @Marimuthu's suggestion, will raise an exception if n
is an out-of-bounds index. The exception comes from !!
.
Upvotes: 4
Reputation: 74374
Caveat emptor if you pick a bad index, but—
dupN n xs = let (first, x:rest) = splitAt (n-1) xs in first ++ x:x:rest
Upvotes: 2
Reputation: 13541
You can also use splitAt:
dupl n xs = first ++ take 1 rest ++ rest where (first, rest) = splitAt (n - 1) xs
This will not break if n
is out of bounds.
Upvotes: 1