简体   繁体   中英

Haskell algorithm for sequence of tuples in a list of lists

I was playing around a bit in Haskell to get familiar with it, but got stuck at the following problem:

I want to define a function that, given a list containing some amount of other lists, each containing 0 or more tuples, creates a new list as following:

*Main> foo 
    [
      [ (1,2), (3,4)  ],
      [ (5,6)         ],
      [ (7,8), (9,10) ]
    ]


  = [
      [ (1,2), (5,6), (7,8)  ],
      [ (1,2), (5,6), (9,10) ],
      [ (3,4), (5,6), (7,8)  ],
      [ (3,4), (5,6), (9,10) ]
    ]

So, in other words, the function should compose a list with every tuple from the first list combined with in each case one of the other tuples in the N remaining lists.

I was trying to write a recursive algorithm for this, but can't wrap my head around dealing with the N amount of other lists to combine tuples with. For just two lists of tuples, I would write something like:

composeList [] _        = []
composeList (x:xs) list = composeTuples x list ++ composeList xs list

composeTuples _ []     = []
composeTuples t (x:xs) = [t,x] : composeTuples t xs

This gives me:

*Main Data.List> composeList [(1,2),(3,4)] [(5,6),(7,8)]

    [
      [ (1,2), (5,6) ],
      [ (1,2), (7,8) ],
      [ (3,4), (5,6) ],
      [ (3,4), (7,8) ]
    ]

Though I can't seem to put the pieces together and make it work for any number of lists, each with any (>=0) number of tuples.

I'm both interested in solving this issue with some of Haskell's predefined functions (if possible), as well as with a somewhat similar approach as the one I was going for in the example above.

Thanks in advance!

This is simply the list monad, selecting an element from each list non-deterministically.

The function you're looking for is sequence :: Monad m => [ma] -> m [a] from Control.Monad

λ. let as = [(1,2),(3,4)]
λ. let bs = [(5,6)]
λ. let cs = [(7,8),(9,10)]
λ. let xss = [as, bs, cs]
λ. sequence xss
  [[(1,2),(5,6),(7,8)]
  ,[(1,2),(5,6),(9,10)]
  ,[(3,4),(5,6),(7,8)]
  ,[(3,4),(5,6),(9,10)]
  ]

Here's a recursive solution

solution :: [[a]] -> [[a]]
solution (x: xs) = [y: ys | y <- x, ys <- solution xs]
solution []      = [[]]

The idea behind the solution is the following: prepend each element of the head of list to every list you get from recursively computing the result for the tail of the input list.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM