私は本当に一般的な方法でcatamorphisms/anamorphismsでの作業のアイデアのように、それはパフォーマンスの大幅な欠点を持っている私には思える:GHCは、異型性などの一般的な機能を最適化(デフォレスト)することは可能ですか?
我々は、カテゴリのようにツリー構造で作業したいとしましょう - 記述するためにジェネリックcatamorphism functionを使用して、異なる折りたたみ:時間:残念ながら、このアプローチは重大な欠点を持っている
depth1 :: Tree -> Int
depth1 = catam g
where
g Leaf = 0
g (Tree l r) = max l r
:
newtype Fix f = Fix { unfix :: f (Fix f) }
data TreeT r = Leaf | Tree r r
instance Functor TreeT where
fmap f Leaf = Leaf
fmap f (Tree l r) = Tree (f l) (f r)
type Tree = Fix TreeT
catam :: (Functor f) => (f a -> a) -> (Fix f -> a)
catam f = f . fmap (catam f) . unfix
今、私たちは以下のように関数を記述することができます新しいレベルのTreeT Int
がfmap
のすべてのレベルで作成され、ただちにg
が消費されます。古典定義
depth2 :: Tree -> Int
depth2 (Fix Leaf) = 0
depth2 (Fix (Tree l r)) = max (depth1 l) (depth1 r)
と比較すると、当社のdepth1
GC上の不要な歪みを作る常に遅くなります。 1つの解決策は、hylomorphismsを使用し、作成ツリーと折り畳みツリーを結合することです。しかし、しばしば私たちはそのことを望んでいません。ツリーをある場所に作成し、後に折り畳まれるように別の場所を通過させたいことがあります。または、異なる異型性を持つフォルダを数回作成することもできます。
GHCを最適化する方法はありますかdepth1
?インライン化のようなものcatam g
そしてfusing/deforestingg . fmap ...
の内部に?
私はこのパーティーに遅れていますが、ツリーの深さを計算する関数の 'g'(または' depth2')の 'Tree'のどこかに' + 1'があるべきではありませんか?それ以外の場合は、 'depth1'や' depth2'がどのようにゼロ以外のものを返すことができるのか分かりません。 –
また、depth2の定義で 'depth1'は実際に' depth2'であるべきだと思います。 –