我有三个列表.让我们说[a,b,c],[d,e]和[f,g,h]现在我想生成所有可能性.结果始终是以下语法:list1 + elem list2 + elem list3中的元素
例如:adf aeg cdf bdf bdg
等等.
我现在不知道.我想使用类似for-each-loop的东西,但它在haskell中没有用^^你有一些tipps来解决这个问题吗?
谢谢!
一种方法是使用列表推导,如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来说,两者都是非常易读和易懂的