有没有一种方法可以生成预先过滤的排列,而不是:
filter condition $ permutations list
排列功能可能会短路。例如:
perms [] = [[]]
perms xs = [ i:j | i <- xs, j <- perms $ delete i xs]
我尝试了一些明显的事情,例如:
perms xs = [ i:j | i <- xs, j <- filter condition $ perms $ delete i xs]
我认为将要发生的事情是,这会引出一条链,该链最终会在[]处出现,然后再进行备份,但是会一直过滤。但是,当输入大量内容时,可以加快处理速度。似乎没有发生这种情况,因为尝试对20个项目列表进行置换时出现了停顿(ghci),而该列表实际上只有很少的经过过滤的置换。
答案 0 :(得分:3)
以do
表示法和递归进行编码非常简单。
foo :: ([a] -> Bool) -> [a] -> [[a]]
foo p xs = bar ([],xs)
where
bar (acc,[]) = return acc
bar (acc,xs) = do
(x,ys) <- picks xs -- shrink the domain (ys)
if ( p (x:acc) ) -- test soon
then bar (x:acc,ys) -- loop
else mzero -- fail early
picks [] = []
picks (x : xs) = (x, xs) : [(y, x : ys) | (y, ys) <- picks xs]
picks
来自this answer。
测试:
> foo (const True) [1..3]
[[3,2,1],[2,3,1],[3,1,2],[1,3,2],[2,1,3],[1,2,3]]
> foo (\(x:xs) -> not(null xs) || x > 1) [1..3]
[[3,1,2],[1,3,2],[2,1,3],[1,2,3]]
最后一个也立即开始为[1..20]
,[1..300]
等产生其输出。
我敢肯定,这可以用更高层次的东西很好地表达出来。