単項演算子の下でコンテナの閉包を計算するための効率的な機能アルゴリズム(好ましくは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)
より効率的な実装は、新しい各段階(「フリンジ」)で生成された要素とのdoesnのトラックを保持しますxs
が[0..19]
の空でない部分リストである場合、closure' (\x->(x+3)`mod`20) xs
は[0..19]であり、反復が安定で、
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)
例として:「tは、それが既に適用された要素に関数を適用しますの20ステップ、[0,1]
の13ステップ、[0,4,8,12,16]
の4ステップ。
ツリーベースの順序付けされた実装を使用すると、さらに効率を上げることができます。 これはすでに完了していますか?バイナリ(またはより高いアリティ)演算子でのクロージャの関連するしかしより困難な問題はどうでしょうか?
をチェックすることは怠惰に関係していますか? –
私が念頭に置いているアプリケーションでは、すでに閉じられている有限集合がどこにあり、サブセットの閉包を計算したいのですか? – lambdacalculator