Search code examples
haskellreplicationlist-comprehension

Haskell concat replicate inside list comprehension


I'm having trouble with the following exercise :

Utilizing list comprehension, define a function with the following signature:

reproduce :: [Int] -> [Int]

This function exchanges the every number in a list by x copies of itself.

eg:

input: reproduce[3,5,1]
output: [3,3,3,5,5,5,5,5,1]

I have done the following:

reproduce :: [Int] -> [Int]
reproduce xs = [ x | x <- [1,2..10 ] , x `elem` xs , replicate x x ]

My line of thought was making x belong to a small interval, x had to be an element of the original list so using elemx would only be added if it did belong to the original list, and replicating x , x times, to get the x copies of himself.

When i try to load this function i get the following error message:

Couldn't match expected type `Bool' with actual type `[Int]'
In the return type of a call of `replicate'
In the expression: replicate x x
In a stmt of a list comprehension: replicate x x

I have no idea how to fix this error, I'm assuming it has something to do with the elem part but I don't know what.

NOTE: This is a beginners exercise and thus should be solved in a simple manner.


Solution

  • A list comprehension consists of a result expression L and one or more comma-separated right-hand forms R1, R2, ... arranged like this:

    [ L | R1, R2, ... ]
    

    Every right-hand side form must be either (1) a generator:

    pattern <- expression
    

    or (2) a let binding:

    let pattern = expression
    

    or (3) a filter condition (an expression returning a Bool):

    expression
    

    In your code we have three such forms. x <- [1,2..10 ] is a generator (case 2), x `elem` xs is a filter condition (case 3), but replicate x x fits none of these. And that's what the error message is about: Haskell expects the expression to have type Bool but replicate returns a list.


    To actually solve the problem, you could start by doing this:

    notQuiteReproduce xs = [ replicate x x | x <- xs ]
    

    Now notQuiteReproduce [3, 5, 1] yields [[3,3,3],[5,5,5,5,5],[1]]. All that's left is to "flatten" the result list. This can also be done with a list comprehension but I'm reluctant to just give the solution away.