Haskell生成预过滤的排列

时间:2018-09-01 02:22:06

标签: haskell

有没有一种方法可以生成预先过滤的排列,而不是:

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),而该列表实际上只有很少的经过过滤的置换。

1 个答案:

答案 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]等产生其输出。

我敢肯定,这可以用更高层次的东西很好地表达出来。