在Haskell中,生成所有列表的最有效方法是什么?
https://stackoverflow.com/a/41929156建议使用以下代码:
interleavings :: [[a]] -> [[a]]
interleavings = go . filter (not . null)
where
go [] = [[]]
go xss = do
(xssl, x : xs, xssr) <- zippers xss
(x :) <$> interleavings ([xs | not (null xs)] ++ xssl ++ xssr)
zippers :: [a] -> [([a], a, [a])]
zippers = go' []
where
go' l (h : r) = (l, h, r) : go' (h : l) r
go' _ [] = []
ghci> interleavings [[1,2,3],[4,5],[6]]
[[1,2,3,4,5,6],[1,2,3,4,6,5],[1,2,3,6,4,5],[1,2,4,5,3,6],[1,2,4,5,6,3],[1,2,4,3,5,6],[1,2,4,3,6,5],[1,2,4,6,3,5],[1,2,4,6,5,3],[1,2,6,4,5,3],[1,2,6,4,3,5],[1,2,6,3,4,5],[1,4,5,2,3,6],[1,4,5,2,6,3],[1,4,5,6,2,3],[1,4,2,3,5,6],[1,4,2,3,6,5],[1,4,2,5,3,6],[1,4,2,5,6,3],[1,4,2,6,5,3],[1,4,2,6,3,5],[1,4,6,2,3,5],[1,4,6,2,5,3],[1,4,6,5,2,3],[1,6,4,5,2,3],[1,6,4,2,3,5],[1,6,4,2,5,3],[1,6,2,3,4,5],[1,6,2,4,5,3],[1,6,2,4,3,5],[4,5,1,2,3,6],[4,5,1,2,6,3],[4,5,1,6,2,3],[4,5,6,1,2,3],[4,1,2,3,5,6],[4,1,2,3,6,5],[4,1,2,5,3,6],[4,1,2,5,6,3],[4,1,2,6,5,3],[4,1,2,6,3,5],[4,1,5,2,3,6],[4,1,5,2,6,3],[4,1,5,6,2,3],[4,1,6,5,2,3],[4,1,6,2,3,5],[4,1,6,2,5,3],[4,6,1,2,3,5],[4,6,1,2,5,3],[4,6,1,5,2,3],[4,6,5,1,2,3],[6,4,5,1,2,3],[6,4,1,2,3,5],[6,4,1,2,5,3],[6,4,1,5,2,3],[6,1,2,3,4,5],[6,1,2,4,5,3],[6,1,2,4,3,5],[6,1,4,5,2,3],[6,1,4,2,3,5],[6,1,4,2,5,3]]
这对于尝试all interleaving程序指令的并发测试很有用。
但是,考虑到Haskell的懒惰计算,以及我们使用单链表的事实,是否有更有效的方法来做到这一点?如果我们不需要同时在内存中存储整个结果,而是只需要在每个交织上计算一个函数,那会怎么样?
1条答案
按热度按时间0md85ypi1#
你可以通过使用数组来使它稍微快一点(在我的测试中快了33%)。
设置:
主要功能:
测试和基准:
使用
ghc -O2 Main.hs
编译测试结果: