Reputation: 1581
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
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
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
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
Reputation: 39906
use List Comprehension:
s = [a,b]
s' = [c,d]
all_combinations = [(x,y) | x <- s, y <- s']
Upvotes: 8
Reputation: 120711
[ (x,y) | x<-[a,b], y<-[c,d] ]
This doesn't really require any further explanation, does it?
Upvotes: 36