【发布时间】:2013-10-21 01:50:36
【问题描述】:
我对用于计算在一元运算符下的容器闭包的高效函数算法(最好是在 Haskell 中,甚至更优选已经作为库的一部分实现!)感兴趣。
对于列表,我想到的一个基本且低效的示例是:
closure :: Ord a => (a -> a) -> [a] -> [a]
closure f xs = first_dup (iterate (\xs -> nub $ sort $ xs ++ map f xs) xs) where
first_dup (xs:ys:rest) = if xs == ys then xs else first_dup (ys:rest)
更高效的实现会跟踪每个阶段(“边缘”)生成的新元素,并且不会将函数应用于已应用的元素:
closure' :: Ord a => (a -> a) -> [a] -> [a]
closure' f xs = stable (iterate close (xs, [])) where
-- return list when it stabilizes, i.e., when fringe is empty
stable ((fringe,xs):iterates) = if null fringe then xs else stable iterates
-- one iteration of closure on (fringe, rest); key invariants:
-- (1) fringe and rest are disjoint; (2) (map f rest) subset (fringe ++ rest)
close (fringe, xs) = (fringe', xs') where
xs' = sort (fringe ++ xs)
fringe' = filter (`notElem` xs') (map f fringe)
例如,如果xs 是[0..19] 的非空子列表,那么closure' (\x->(x+3)`mod`20) xs 是[0..19],对于[0],迭代稳定在20 步,对于[0,1],迭代稳定在13 步, 以及 [0,4,8,12,16] 的 4 个步骤。
使用基于树的有序集实现可以获得更高的效率。 这已经完成了吗?对于二元(或更高元数)运算符下的闭包这个相关但更难的问题呢?
【问题讨论】:
-
懒惰重要吗?
-
不在我心目中的应用程序中,我有已经关闭的有限集,我想计算子集的关闭。
标签: algorithm haskell functional-programming