(possibly) a list comprehensions question

Hi Cafe! I am struggling with an interesting problem while defining a function. It looks quite easy to me, but I couldn't manage to have a proper implementation yet. To illustrate what I'm trying to achive, I'll introduce special cases of the desired function, and hopefully build towards a solution step by step. -- simplest case, taking 2 lists as parameters and returning a list of list containing every possible pair (but represented as lists) allPossibilities2 :: [a] -> [a] -> [[a]] allPossibilities2 listX listY = [ [x,y] | x <- listX, y <- listY] -- sample output -- allPossibilities2 [1,2,3] [7,8,9] -- [[1,7],[1,8],[1,9],[2,7],[2,8],[2,9],[3,7],[3,8],[3,9]] -- simplest case with 3 parameters instead of 2 allPossibilities3 :: [a] -> [a] -> [a] -> [[a]] allPossibilities3 listX listY listZ = [ [x,y,z] | x <- listX, y <- listY, z <- listZ] -- allPossibilities3 [1,2] [3,4,5] [6,7] -- [[1,3,6],[1,3,7],[1,4,6],[1,4,7],[1,5,6],[1,5,7],[2,3,6],[2,3,7],[2,4,6],[2,4,7],[2,5,6],[2,5,7]] These are easy and work just fine. All I want to do is to generalize this function receiving n lists as parameters and doing the simple action described above. Since I cannot pass variable number of parameters to a function, I'll use list of lists from now on. Following are the implementations of the same functions with different types (instead of two lists, a list of lists assumed to caontain those 2 elements) allPossibilities2' :: [[a]] -> [[a]] allPossibilities2' list = [ [x,y] | x <- list !! 0, y <- list !! 1] -- allPossibilities2' [[1,2,3],[7,8,9]] -- [[1,7],[1,8],[1,9],[2,7],[2,8],[2,9],[3,7],[3,8],[3,9]] allPossibilities3' :: [[a]] -> [[a]] allPossibilities3' list = [ [x,y,z] | x <- list !! 0, y <- list !! 1, z <- list !! 2] -- allPossibilities3' [[1,2],[3,4,5],[6,7]] -- [[1,3,6],[1,3,7],[1,4,6],[1,4,7],[1,5,6],[1,5,7],[2,3,6],[2,3,7],[2,4,6],[2,4,7],[2,5,6],[2,5,7]] This is ugly! Anyway, just forget the fact that these funstions do not do a check on the length of the input list for a moment. My question is, how can I generalize this function to accept a list of lists of arbitrary length, and produce the required result. I hope I managed to make my point clear enough. Waiting for suggestions. Regards, -- Ozgur Akgun

You can easily use "sequence". The less easy part is understanding why
it works. Are you familiar with monads? If you are not, try to take
the source code of 'sequence', inline it and understand why *that*
works.
Prelude> map sum $ sequence [[1,2], [10,20], [100,200]]
[111,211,121,221,112,212,122,222]
2009/11/19 Ozgur Akgun
Hi Cafe!
I am struggling with an interesting problem while defining a function. It looks quite easy to me, but I couldn't manage to have a proper implementation yet. To illustrate what I'm trying to achive, I'll introduce special cases of the desired function, and hopefully build towards a solution step by step.
-- simplest case, taking 2 lists as parameters and returning a list of list containing every possible pair (but represented as lists) allPossibilities2 :: [a] -> [a] -> [[a]] allPossibilities2 listX listY = [ [x,y] | x <- listX, y <- listY]
-- sample output -- allPossibilities2 [1,2,3] [7,8,9] -- [[1,7],[1,8],[1,9],[2,7],[2,8],[2,9],[3,7],[3,8],[3,9]]
-- simplest case with 3 parameters instead of 2 allPossibilities3 :: [a] -> [a] -> [a] -> [[a]] allPossibilities3 listX listY listZ = [ [x,y,z] | x <- listX, y <- listY, z <- listZ]
-- allPossibilities3 [1,2] [3,4,5] [6,7] -- [[1,3,6],[1,3,7],[1,4,6],[1,4,7],[1,5,6],[1,5,7],[2,3,6],[2,3,7],[2,4,6],[2,4,7],[2,5,6],[2,5,7]]
These are easy and work just fine. All I want to do is to generalize this function receiving n lists as parameters and doing the simple action described above. Since I cannot pass variable number of parameters to a function, I'll use list of lists from now on. Following are the implementations of the same functions with different types (instead of two lists, a list of lists assumed to caontain those 2 elements)
allPossibilities2' :: [[a]] -> [[a]] allPossibilities2' list = [ [x,y] | x <- list !! 0, y <- list !! 1]
-- allPossibilities2' [[1,2,3],[7,8,9]] -- [[1,7],[1,8],[1,9],[2,7],[2,8],[2,9],[3,7],[3,8],[3,9]]
allPossibilities3' :: [[a]] -> [[a]] allPossibilities3' list = [ [x,y,z] | x <- list !! 0, y <- list !! 1, z <- list !! 2]
-- allPossibilities3' [[1,2],[3,4,5],[6,7]] -- [[1,3,6],[1,3,7],[1,4,6],[1,4,7],[1,5,6],[1,5,7],[2,3,6],[2,3,7],[2,4,6],[2,4,7],[2,5,6],[2,5,7]]
This is ugly!
Anyway, just forget the fact that these funstions do not do a check on the length of the input list for a moment. My question is, how can I generalize this function to accept a list of lists of arbitrary length, and produce the required result.
I hope I managed to make my point clear enough. Waiting for suggestions.
Regards,
-- Ozgur Akgun
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- Eugene Kirpichov Web IR developer, market.yandex.ru

Ozgur Akgun wrote:
Anyway, just forget the fact that these funstions do not do a check on the length of the input list for a moment. My question is, how can I generalize this function to accept a list of lists of arbitrary length, and produce the required result.
Hi, The concise solution is the list monad, as already posted. If that confuses you, here is a version using list comprehensions (well, mostly): allPossibilities :: [[a]] -> [[a]] allPossibilities [] = [[]] allPossibilities (l:ls) = [ x : xs | x <- l, xs <- allPossibilities ls] The second line prefixes all possibilities from the later lists with every element from the the first list. Note that the base-case is crucial; if it is the empty list [], that "xs <- allPossibilities ls" will not find any elements, and thus the list comprehension becomes the empty list, and the whole thing falls apart. Thus the base case must be the list containing the empty list, so that you have one possibility arising at the end upon which to prefix the items. Hope that makes sense... Thanks, Neil.

Thanks for the both quick answers.
This is what happens all the time, the thing I am trying to implement is
already in the library!
Neil,
I clearly understood the way you implemented. Actually I had a similar
implementation with some problems, one of which is the base-case you
mentioned.
Eugene,
I'll definitely have a look at the implementation of sequence.
Cheers!
2009/11/19 Neil Brown
Ozgur Akgun wrote:
Anyway, just forget the fact that these funstions do not do a check on the length of the input list for a moment. My question is, how can I generalize this function to accept a list of lists of arbitrary length, and produce the required result.
Hi,
The concise solution is the list monad, as already posted. If that confuses you, here is a version using list comprehensions (well, mostly):
allPossibilities :: [[a]] -> [[a]] allPossibilities [] = [[]] allPossibilities (l:ls) = [ x : xs | x <- l, xs <- allPossibilities ls]
The second line prefixes all possibilities from the later lists with every element from the the first list. Note that the base-case is crucial; if it is the empty list [], that "xs <- allPossibilities ls" will not find any elements, and thus the list comprehension becomes the empty list, and the whole thing falls apart. Thus the base case must be the list containing the empty list, so that you have one possibility arising at the end upon which to prefix the items. Hope that makes sense...
Thanks,
Neil.
-- Ozgur Akgun

This is what happens all the time, the thing I am trying to implement is already in the library!
You can easily find those library functions using Hoogle.
In this case Hoogle gives the "sequence" function as its second result
for the query "[[a]] -> [[a]]":
Data.List transpose :: [[a]] -> [[a]]
Prelude sequence :: Monad m => [m a] -> m [a]
See: http://haskell.org/hoogle/?hoogle=%5B%5Ba%5D%5D+-%3E+%5B%5Ba%5D%5D
On Nov 19, 3:58 pm, Ozgur Akgun
Thanks for the both quick answers.
This is what happens all the time, the thing I am trying to implement is already in the library!
Neil, I clearly understood the way you implemented. Actually I had a similar implementation with some problems, one of which is the base-case you mentioned.
Eugene, I'll definitely have a look at the implementation of sequence.
Cheers!
2009/11/19 Neil Brown
Ozgur Akgun wrote:
Anyway, just forget the fact that these funstions do not do a check on the length of the input list for a moment. My question is, how can I generalize this function to accept a list of lists of arbitrary length, and produce the required result.
Hi,
The concise solution is the list monad, as already posted. If that confuses you, here is a version using list comprehensions (well, mostly):
allPossibilities :: [[a]] -> [[a]] allPossibilities [] = [[]] allPossibilities (l:ls) = [ x : xs | x <- l, xs <- allPossibilities ls]
The second line prefixes all possibilities from the later lists with every element from the the first list. Note that the base-case is crucial; if it is the empty list [], that "xs <- allPossibilities ls" will not find any elements, and thus the list comprehension becomes the empty list, and the whole thing falls apart. Thus the base case must be the list containing the empty list, so that you have one possibility arising at the end upon which to prefix the items. Hope that makes sense...
Thanks,
Neil.
-- Ozgur Akgun
_______________________________________________ Haskell-Cafe mailing list Haskell-C...@haskell.orghttp://www.haskell.org/mailman/listinfo/haskell-cafe

You're right. I do that sometimes, but I must make a habit of "hoogling".
2009/11/19 yairchu@gmail.com
This is what happens all the time, the thing I am trying to implement is already in the library!
You can easily find those library functions using Hoogle. In this case Hoogle gives the "sequence" function as its second result for the query "[[a]] -> [[a]]":
Data.List transpose :: [[a]] -> [[a]] Prelude sequence :: Monad m => [m a] -> m [a]
See: http://haskell.org/hoogle/?hoogle=%5B%5Ba%5D%5D+-%3E+%5B%5Ba%5D%5D
Thanks for the both quick answers.
This is what happens all the time, the thing I am trying to implement is already in the library!
Neil, I clearly understood the way you implemented. Actually I had a similar implementation with some problems, one of which is the base-case you mentioned.
Eugene, I'll definitely have a look at the implementation of sequence.
Cheers!
2009/11/19 Neil Brown
Ozgur Akgun wrote:
Anyway, just forget the fact that these funstions do not do a check on
length of the input list for a moment. My question is, how can I generalize this function to accept a list of lists of arbitrary length, and
required result.
Hi,
The concise solution is the list monad, as already posted. If that confuses you, here is a version using list comprehensions (well, mostly):
allPossibilities :: [[a]] -> [[a]] allPossibilities [] = [[]] allPossibilities (l:ls) = [ x : xs | x <- l, xs <- allPossibilities ls]
The second line prefixes all possibilities from the later lists with every element from the the first list. Note that the base-case is crucial; if it is the empty list [], that "xs <- allPossibilities ls" will not find any elements, and thus the list comprehension becomes the empty list, and
On Nov 19, 3:58 pm, Ozgur Akgun
wrote: the produce the the whole thing falls apart. Thus the base case must be the list containing the empty list, so that you have one possibility arising at the end upon which to prefix the items. Hope that makes sense...
Thanks,
Neil.
-- Ozgur Akgun
_______________________________________________ Haskell-Cafe mailing list Haskell-C...@haskell.orghttp:// www.haskell.org/mailman/listinfo/haskell-cafe
Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- Ozgur Akgun
participants (4)
-
Eugene Kirpichov
-
Neil Brown
-
Ozgur Akgun
-
yairchu@gmail.com