smbl
smbl

Reputation: 334

Haskell List Comprehension using different variables

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?

Upvotes: 1

Views: 653

Answers (2)

Random Dev
Random Dev

Reputation: 52280

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 ;)

Upvotes: 4

Nyavro
Nyavro

Reputation: 8866

You can use zip to provide items with indexes:

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

Upvotes: 3

Related Questions