1

Hi I am trying to implement a simple function that does this with list comprehension:

duplicate "asdf" = "assdff"

duplicate "123456" = "122344566"

and this is what I came up with

duplicate xs = 
   [ y | x <- xs
       , i <- [0..]
       , y <- if i `mod` 2 == 0 
              then replicate 2 x 
              else x ]

I wanted i to act as a counter to keep track of the position of the list, and x to hold the list.

Is there a way to make this work?

2 Answers 2

4

The reason yours is not working is that your else branch does not produce an list inside your function - you can easily fix the syntax issue like this:

duplicate xs = 
   [ y | x <- xs
       , i <- [0..]
       , y <- if i `mod` 2 == 0 
              then replicate 2 x 
              else [x] ]

but this would give you nothing but an endless list of the first thing in xs (because there are infinite many is)

Now my guess is that you indeed want to replicate every other element 2 times and yes zip is a great idea and you are almost there (with your comment):

just make sure that you fix the syntax/type error there as well:

duplicate xs = 
   [ y | (i, x) <- zip [0..] xs
       , y <- if i `mod` 2 == 0 
              then replicate 2 x 
              else [x] ]

this will give you:

λ> duplicate "Hello" 
"HHellloo"

which is hopefully what you are looking for


exercise

You can rewrite this into

duplicate = concat . zipWith replicate (cycle [2, 1])

try to find out how this works

Hint: it's based on the idea of: take 2 of the first, then 1 of the second, then 2 of the third, then 1 of the forth, ... - only obfuscated by Haskells higher-order function and operator zoo ;)

Sign up to request clarification or add additional context in comments.

5 Comments

Why not concat . zipWith replicate (cycle [1,2])?
nice too ;) (should have thought things trough)
@Zeta: shamelessly stole yours - there was an issue with the order anyway (as it seems that the first item should be duplicated)
I think "Hello" is supposed to become "Heelllo", not "HHellloo" (duplicating positions 0, 2, 4, ..., not 1, 3, 5, ...).
@chepner the H is at position 0 if you zip with [0...] - the OP used this (i <- [0..]) as well and indeed I had it the other way around first - anyway it does not really matter as you can easily fix it bei either starting with [1...] or for the other form by switching [2,1] into [1,2]
3

You can use zip to provide items with indexes:

Prelude> zip "asdf" [0..]
[('a',0),('s',1),('d',2),('f',3)]

1 Comment

hmm so I tried this: duplicate xs = [ y | (x,i) <- zip xs [0..], y <- if i mod` 2 == 0 then replicate 2 x else x ]` but it seems not to be working..

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.