Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell list comprehension on variable number of strings

If I have two strings I use a list comprehension to obtain the desired result:

 combineStrings firstStr sndStr = [ [a,b] | a <- firstStr, b <- sndStr]

For three strings, I use this

 combineStrings firstStr sndStr trdStr = [ [a,b,c] | a <- firstStr, b <- sndStr, c <- trdStr]

What I'm trying is to obtain the same result for a variable number of strings. For example if I have a function which takes the following form:

 combineStrings :: [String] -> [String]

I'm trying to obtain the same results as above for 2, 3 ... n lists... I tried multiple ways, like this one

 combineStrings []      = []
 combineStrings (hd:tl) = [ a:b | a <- hd, b <- combineStrings tl]

but this fails because of [] on the first clause. Can someone help me to write this, please?

like image 261
Adi Avatar asked Jan 04 '12 14:01

Adi


2 Answers

Noteworthy: Haskell already has that function, just a bit more general:

Prelude> :t sequence
sequence :: Monad m => [m a] -> m [a]
Prelude> sequence ["ab","cd","12"]
["ac1","ac2","ad1","ad2","bc1","bc2","bd1","bd2"]

[] is an instance of Monad, so in this case the signature becomes sequence :: [[a]] -> [[a]], with a = Char, sequence :: [String] -> [String].

like image 110
Daniel Fischer Avatar answered Oct 06 '22 09:10

Daniel Fischer


Try

combineStrings [] = [""]

or better (as pointed out by sdcwc):

combineStrings [] = [[]]

Otherwise the part b <- combineStrings tl of the list comprehension will not yield any b and you will always end up with an empty array.

It also makes sense as an edge case: The only way to combine characters from zero strings is an empty string (consisting of zero characters).

like image 41
undur_gongor Avatar answered Oct 06 '22 09:10

undur_gongor