정말 일반적인 방법으로 catamorphisms/anamorphisms 작업의 생각처럼,하지만 그것은 상당한 성능 단점이있다 나에게 보인다GHC를 변형 (catamorphisms)과 같은 일반 함수 (deforest)로 최적화 할 수 있습니까?
가정 해 우리는 무조건적인 방법으로 트리 구조 작업 할이 - 설명하는 사용하여 다른 접이식 일반적인 catamorphism function :
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
이제 우리는 같은 기능을 쓸 수는 :
depth1 :: Tree -> Int
depth1 = catam g
where
g Leaf = 0
g (Tree l r) = max l r
불행하게도,이 방법은 큰 단점이있다 : 지속 시간 계산을 수행하면 TreeT Int
의 새 인스턴스가 g
에 의해 즉시 사용되도록 fmap
의 모든 레벨에서 생성됩니다. 고전적인 정의
depth2 :: Tree -> Int
depth2 (Fix Leaf) = 0
depth2 (Fix (Tree l r)) = max (depth1 l) (depth1 r)
에 비해 우리의 depth1
GC의에 불필요한 부담을 항상 느립니다. 한 가지 해결책은 hylomorphisms을 사용하고 생성 및 폴딩 트리를 함께 결합하는 것입니다. 그러나 종종 그렇게하고 싶지는 않습니다. 한 곳에서 나무를 만들고 나중에 다른 곳으로 옮겨서 나무를 접기를 원할 수도 있습니다. 또는 여러 가지 변형 된 형태로 폴더를 여러 번 만들 수 있습니다.
GHC를 최적화하는 방법이 있습니까 depth1
? 인라인처럼 뭔가 catam g
다음 fusing/deforestingg . fmap ...
안에?
나는이 파티에 늦었지만 트리의 깊이를 계산하는 함수의'g' (또는'depth2')의'Tree' 경우 어딘가에 '+ 1'이 없어야합니까? 그렇지 않으면'depth1' 또는'depth2'가 어떻게 0을 반환 할 수 있는지 알 수 없습니다. –
또한'depth2'의 정의에서'depth1'은 실제로'depth2'라고 생각합니다. –