我很感兴趣的是高效的函数式算法(最好是在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步。使用基于树的有序集合实现,可以进一步提高效率。 这个是否已经完成了?而对于二元(或更高元)运算符下的闭包,相关但更难的问题是什么?