@@ -211,10 +211,7 @@ instance Foldable Tree where
211211
212212 foldr f z = \ t -> go t z -- Use a lambda to allow inlining with two arguments
213213 where
214- go (Node x ts) = f x . foldr (\ t k -> go t . k) id ts
215- -- This is equivalent to the following simpler definition, but has been found to optimize
216- -- better in benchmarks:
217- -- go (Node x ts) z' = f x (foldr go z' ts)
214+ go (Node x ts) z' = f x (foldrTreeList go z' ts)
218215 {-# INLINE foldr #-}
219216
220217 foldl' f = go
@@ -243,6 +240,17 @@ instance Foldable Tree where
243240 product = foldlMap1' id (*)
244241 {-# INLINABLE product #-}
245242
243+ -- This is the same as List's foldr, but unlike GHC's implementation the z is
244+ -- passed along in go instead of go closing over it.
245+ -- When folding over a Tree this avoids a closure per Node, which results in
246+ -- significant reductions in time and allocations according to benchmarks.
247+ foldrTreeList :: (Tree a -> b -> b ) -> b -> [Tree a ] -> b
248+ foldrTreeList f = go
249+ where
250+ go z [] = z
251+ go z (t: ts) = f t (go z ts)
252+ {-# INLINE foldrTreeList #-}
253+
246254#if MIN_VERSION_base(4,18,0)
247255-- | Folds in pre-order.
248256--
@@ -571,7 +579,7 @@ leaves :: Tree a -> [a]
571579#ifdef __GLASGOW_HASKELL__
572580leaves t = GHC.Exts. build $ \ cons nil ->
573581 let go (Node x [] ) z = cons x z
574- go (Node _ ts) z = foldr go z ts
582+ go (Node _ ts) z = foldrTreeList go z ts
575583 in go t nil
576584{-# INLINE leaves #-} -- Inline for list fusion
577585#else
@@ -607,8 +615,9 @@ leaves t =
607615edges :: Tree a -> [(a , a )]
608616#ifdef __GLASGOW_HASKELL__
609617edges (Node x0 ts0) = GHC.Exts. build $ \ cons nil ->
610- let go p = foldr (\ (Node x ts) z -> cons (p, x) (go x z ts))
611- in go x0 nil ts0
618+ let go _ [] z = z
619+ go p (Node x' ts' : ts) z = cons (p, x') (go x' ts' (go p ts z))
620+ in go x0 ts0 nil
612621{-# INLINE edges #-} -- Inline for list fusion
613622#else
614623edges (Node x0 ts0) =
@@ -723,7 +732,7 @@ instance Foldable PostOrder where
723732
724733 foldr f z0 = \ (PostOrder t) -> go t z0 -- Use a lambda to inline with two arguments
725734 where
726- go (Node x ts) z = foldr go (f x z) ts
735+ go (Node x ts) z = foldrTreeList go (f x z) ts
727736 {-# INLINE foldr #-}
728737
729738 foldl' f z0 = \ (PostOrder t) -> go z0 t -- Use a lambda to inline with two arguments
@@ -778,7 +787,7 @@ instance Foldable1.Foldable1 PostOrder where
778787 where
779788 go (Node x [] ) z = x :| z
780789 go (Node x (t: ts)) z =
781- go t (foldr (\ t' z' -> foldr (:) z' (PostOrder t')) (x: z) ts)
790+ go t (foldrTreeList (\ t' z' -> foldr (:) z' (PostOrder t')) (x: z) ts)
782791
783792 maximum = Foldable. maximum
784793 {-# INLINABLE maximum #-}
0 commit comments