Ben
Ben

Reputation: 1581

All combinations of elements of two lists in Haskell

Given two lists, [a, b] and [c, d], I'd like to get the following result:

[(a,c), (a,d), (b,c), (b,d)]

How can I do this in Haskell? Is there a built-in function for this, or should I implement one myself?

Upvotes: 25

Views: 17757

Answers (5)

jub0bs
jub0bs

Reputation: 66234

Applicative style all the way!

λ> :m + Control.Applicative
λ> (,) <$> ['a','b'] <*> ['c','d']
[('a','c'),('a','d'),('b','c'),('b','d')]

(I've eschewed any String syntactic sugar above, in order to stay close to your example.)

For information, (,) is special syntax for a function that takes two arguments and makes a pair out of them:

λ> :t (,)
(,) :: a -> b -> (a, b)

Edit: As noted by leftaroundabout in his comment, you can also use liftA2:

λ> :m + Control.Applicative
λ> let combine = liftA2 (,)
λ> combine "ab" "cd"
[('a','c'),('a','d'),('b','c'),('b','d')]

Upvotes: 23

concept3d
concept3d

Reputation: 2278

The most inuitive would be using list comprehension, other aproaches include using applicative functors:

(,) <$> [1,2,3] <*> [4,5,6]

So what does this do?

Remember that (,) :: a -> b -> (a, b) Takes two arguments and returns a tuple.

<$> is acutally fmap, (<$>) :: Functor f => (a -> b) -> f a -> f b It takes a function and lift it. In this case it takes (,) and lift it to work on list. So let x = (,) <$> [1,2] would generate x :: [b -> (Integer, b)] which is the the list of functions that takes b and returns tuple with one fixed argument (Integer,b). Finally we apply it using <*> to generate all the combinations.

Upvotes: 10

Will Ness
Will Ness

Reputation: 71065

How can you do this in an imperative pseudocode?

for each element x in [a,b]:
    for each element y in [c,d]:
        produce (x,y)

In Haskell, this is written as

outerProduct xs ys =
   do
       x <- xs          -- for each x drawn from xs:
       y <- ys          --   for each y drawn from ys:
       return (x,y)     --      produce the (x,y) pair

(following comments by leftaroundabout) this is of course extremely close to how liftM2 monadic combinator is defined, so in fact

outerProduct = liftM2 (,)

which is the same as liftA2 (,), and its various re-writes in terms of list comprehensions, concatMap function, >>=, <$> and <*> operators.

Conceptually though this is the stuff of the Applicative – which would be better named as Pairing, – because this pairing up of the elements of two "containers" ⁄ "carriers" ⁄ whatever is exactly what Applicative Functor is about. It just so happens that Haskell's do notation works for monads, and not (yet) for applicatives.

In some sense compile-time nested loops are Applicative ⁄ Pairing functors; Monads add the ability to create nested loops on the fly, depending on the values produced by an "outer" enumeration.

Upvotes: 12

Stephane Rolland
Stephane Rolland

Reputation: 39906

use List Comprehension:

s = [a,b]
s' = [c,d]

all_combinations = [(x,y) | x <- s, y <- s']

Upvotes: 8

leftaroundabout
leftaroundabout

Reputation: 120711

[ (x,y) | x<-[a,b], y<-[c,d] ]

This doesn't really require any further explanation, does it?

Upvotes: 36

Related Questions