All combinations of elements of two lists in Haskell

左心房为你撑大大i 提交于 2019-12-03 01:45:45
[ (x,y) | x<-[a,b], y<-[c,d] ]

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

jub0bs

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')]

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.

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.

use List Comprehension:

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

all_combinations = [(x,y) | x <- s, y <- s']
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!