All combinations of elements of two lists in Haskell

前端 未结 5 1086
情歌与酒
情歌与酒 2020-12-30 03:42

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

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


        
相关标签:
5条回答
  • 2020-12-30 04:14

    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.

    0 讨论(0)
  • 2020-12-30 04:15

    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')]
    
    0 讨论(0)
  • 2020-12-30 04:17

    use List Comprehension:

    s = [a,b]
    s' = [c,d]
    
    all_combinations = [(x,y) | x <- s, y <- s']
    
    0 讨论(0)
  • 2020-12-30 04:23
    [ (x,y) | x<-[a,b], y<-[c,d] ]
    

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

    0 讨论(0)
  • 2020-12-30 04:24

    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.

    0 讨论(0)
提交回复
热议问题