Haskell - 就像每个循环一样

fuu*_*man 1 haskell for-loop

我有三个列表.让我们说[a,b,c],[d,e]和[f,g,h]现在我想生成所有可能性.结果始终是以下语法:list1 + elem list2 + elem list3中的元素

例如:adf aeg cdf bdf bdg

等等.

我现在不知道.我想使用类似for-each-loop的东西,但它在haskell中没有用^^你有一些tipps来解决这个问题吗?

谢谢!

bhe*_*ilr 9

一种方法是使用列表推导,如user2407038所建议的那样

allCombinations1 xs ys zs = [(x, y, z) | x <- xs, y <- ys, z <- zs]
Run Code Online (Sandbox Code Playgroud)

同样,这个列表理解也涉及到monadic代码

allCombinations2 xs ys zs = do
    x <- xs
    y <- ys
    z <- zs
    return (x, y, z)
Run Code Online (Sandbox Code Playgroud)

这相当于用liftM3来自Control.Monad:

allCombinations3 = liftM3 (\x y z -> (x, y, z))
Run Code Online (Sandbox Code Playgroud)

您还可以使用forM和执行命令式样式的相同操作concat:

allCombinations4 xs ys zs = concat . concat . concat $
    forM xs $ \x ->
        forM ys $ \y ->
            forM zs $ \z ->
                return (x, y, z)
Run Code Online (Sandbox Code Playgroud)

但这可能比较慢,而且肯定不是惯用的Haskell代码.或者,您也可以使用sequence任意数量的输入,这当然是最通用和最短的:

allCombinations5 :: [[a]] -> [[a]]
allCombinations5 = sequence
Run Code Online (Sandbox Code Playgroud)

测试它们:

> allCombinations1 [1, 2] [3, 4] [5, 6]
[(1,3,5),(1,3,6),(1,4,5),(1,4,6),(2,3,5),(2,3,6),(2,4,5),(2,4,6)]
> allCombinations2 [1, 2] [3, 4] [5, 6]
[(1,3,5),(1,3,6),(1,4,5),(1,4,6),(2,3,5),(2,3,6),(2,4,5),(2,4,6)]
> allCombinations3 [1, 2] [3, 4] [5, 6]
[(1,3,5),(1,3,6),(1,4,5),(1,4,6),(2,3,5),(2,3,6),(2,4,5),(2,4,6)]
> allCombinations4 [1, 2] [3, 4] [5, 6]
[(1,3,5),(1,3,6),(1,4,5),(1,4,6),(2,3,5),(2,3,6),(2,4,5),(2,4,6)]
> allCombinations5 [[1, 2], [3, 4], [5, 6]]
[[1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,3,5],[2,3,6],[2,4,5],[2,4,6]]
Run Code Online (Sandbox Code Playgroud)

请注意,最后一个不返回元组列表而是返回列表列表,因为它可用于获取N个输入的差异组合,而不是固定数量的输入.

像Haskell中的大多数事情一样,这个问题可以通过多种方式解决,我确信甚至还有其他方法可以添加到此列表中.就个人而言,sequence如果您想要任意数量的输入,或者列表理解形式,我建议使用.对于其他Haskeller来说,两者都是非常易读和易懂的