Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you create more than one element of a list at a time with a list comprehension in haskell?

So, for example, say I had a list of numbers and I wanted to create a list that contained each number multiplied by 2 and 3. Is there any way to do something like the following, but get back a single list of numbers instead of a list of lists of numbers?

mult_nums = [ [(n*2),(n*3)] | n <- [1..5]] 
-- this returns [[2,3],[4,6],[6,9],[8,12],[10,15]]
-- but we want [2,3,4,6,6,9,8,12,10,15]
like image 742
Paul Wicks Avatar asked Feb 20 '09 00:02

Paul Wicks


People also ask

How do list comprehensions work in Haskell?

List comprehension in Haskell is a way to produce the list of new elements from the generator we have passed inside it. Also for the generator values, we can apply the Haskell functions to modify it later. This list comprehension is very y easy to use and handle for developers and beginners as well.

How do you make an infinite list in Haskell?

But in Haskell, you only need to allocate space for the items in the list that actually get evaluated. The two most basic functions for creating an infinite list are "repeat" and "cycle". The first makes an infinite number of the same element, while the second allows you to cycle through a specific series of elements.

How do you get the first element of a list in Haskell?

Finding / searching 0 will result in 1 . (Related: head xs returns the first element of the list.) (Related: last xs returns the last element of the list.)


2 Answers

I find that extending the list comprehension makes this easier to read:

[ m | n <- [1..5], m <- [2*n,3*n] ]

It might be helpful to examine exactly what this does, and how it relates to other solutions. Let's define it as a function:

mult lst = [ m | n <- lst, m <- [2*n,3*n] ]

After a fashion, this desugars to

mult' lst = 
    concatMap (\n -> concatMap (\m -> [m]) [2*n,3*n]) lst

The expression concatMap (\m -> [m]) is wrapping m up in a list in order to immediately flatten it—it is equivalent to map id.

Compare this to @FunctorSalad's answer:

mult1 lst = concatMap (\n -> [n*2,n*3]) lst

We've optimized away concatMap (\m -> [m]).

Now @vili's answer:

mult2 lst = concat [ [(n*2),(n*3)] | n <- lst]

This desugars to:

mult2' lst = concat (concatMap (\n -> [[2*n,3*n]]) lst)

As in the first solution above, we are unnecessarily creating a list of lists that we have to concat away.

I don't think there is a solution that uses list comprehensions, but desugars to mult1. My intuition is that Haskell compilers are generally clever enough that this wouldn't matter (or, alternatively, that unnecessary concats are cheap due to lazy evaluation (whereas they're lethal in eager languages)).

like image 188
Chris Conway Avatar answered Sep 28 '22 00:09

Chris Conway


you could use concat.

concat [ [(n*2),(n*3)] | n <- [1..5]] 
output: [2,3,4,6,6,9,8,12,10,15]
like image 41
vili Avatar answered Sep 28 '22 00:09

vili