{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE CPP #-}
#if __GLASGOW_HASKELL__
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveLift #-}
{-# LANGUAGE Trustworthy #-}
#endif

#include "containers.h"

-----------------------------------------------------------------------------
-- |
-- Module      :  Data.Tree
-- Copyright   :  (c) The University of Glasgow 2002
-- License     :  BSD-style (see the file libraries/base/LICENSE)
--
-- Maintainer  :  libraries@haskell.org
-- Portability :  portable
--
-- = Multi-way Trees and Forests
--
-- The @'Tree' a@ type represents a lazy, possibly infinite, multi-way tree
-- (also known as a /rose tree/).
--
-- The @'Forest' a@ type represents a forest of @'Tree' a@s.
--
-----------------------------------------------------------------------------

module Data.Tree(

    -- * Trees and Forests
      Tree(..)
    , Forest
    , PostOrder(..)

    -- * Construction
    , unfoldTree
    , unfoldForest
    , unfoldTreeM
    , unfoldForestM
    , unfoldTreeM_BF
    , unfoldForestM_BF

    -- * Elimination
    , foldTree
    , flatten
    , levels
    , leaves
    , edges
    , pathsToRoot
    , pathsFromRoot

    -- * Ascii Drawings
    , drawTree
    , drawForest

    ) where

import Utils.Containers.Internal.Prelude as Prelude
import Prelude ()
import Data.Bits ((.&.))
import Data.Foldable (toList)
import qualified Data.Foldable as Foldable
import Data.List.NonEmpty (NonEmpty(..))
import Data.Traversable (foldMapDefault)
import Control.Monad (liftM)
import Control.Monad.Fix (MonadFix (..), fix)
import Data.Sequence (Seq, empty, singleton, (<|), (|>), fromList,
            ViewL(..), ViewR(..), viewl, viewr)
import Control.DeepSeq (NFData(rnf),NFData1(liftRnf))

#ifdef __GLASGOW_HASKELL__
import Data.Data (Data)
import GHC.Generics (Generic, Generic1)
import qualified GHC.Exts
import Language.Haskell.TH.Syntax (Lift)
-- See Note [ Template Haskell Dependencies ]
import Language.Haskell.TH ()
#endif

import Control.Monad.Zip (MonadZip (..))

#ifdef __GLASGOW_HASKELL__
import Data.Coerce (coerce)
#endif
import Data.Functor.Classes

#if !MIN_VERSION_base(4,11,0)
import Data.Semigroup (Semigroup (..))
#endif

#if MIN_VERSION_base(4,18,0)
import qualified Data.Foldable1 as Foldable1
#endif

-- | Non-empty, possibly infinite, multi-way trees; also known as /rose trees/.
data Tree a = Node {
        rootLabel :: a,         -- ^ label value
        subForest :: [Tree a]   -- ^ zero or more child trees
    }
#ifdef __GLASGOW_HASKELL__
  deriving ( Eq
           , Ord -- ^ @since 0.6.5
           , Read
           , Show
           , Data
           , Generic  -- ^ @since 0.5.8
           , Generic1 -- ^ @since 0.5.8
           , Lift -- ^ @since 0.6.6
           )
#else
  deriving (Eq, Ord, Read, Show)
#endif

-- | This type synonym exists primarily for historical
-- reasons.
type Forest a = [Tree a]

-- | @since 0.5.9
instance Eq1 Tree where
  liftEq eq = leq
    where
      leq (Node a fr) (Node a' fr') = eq a a' && liftEq leq fr fr'

-- | @since 0.5.9
instance Ord1 Tree where
  liftCompare cmp = lcomp
    where
      lcomp (Node a fr) (Node a' fr') = cmp a a' <> liftCompare lcomp fr fr'

-- | @since 0.5.9
instance Show1 Tree where
  liftShowsPrec shw shwl p (Node a fr) = showParen (p > 10) $
        showString "Node {rootLabel = " . shw 0 a . showString ", " .
          showString "subForest = " . liftShowList shw shwl fr .
          showString "}"

-- | @since 0.5.9
instance Read1 Tree where
  liftReadsPrec rd rdl p = readParen (p > 10) $
    \s -> do
      ("Node", s1) <- lex s
      ("{", s2) <- lex s1
      ("rootLabel", s3) <- lex s2
      ("=", s4) <- lex s3
      (a, s5) <- rd 0 s4
      (",", s6) <- lex s5
      ("subForest", s7) <- lex s6
      ("=", s8) <- lex s7
      (fr, s9) <- liftReadList rd rdl s8
      ("}", s10) <- lex s9
      pure (Node a fr, s10)

instance Functor Tree where
    fmap = fmapTree
    x <$ Node _ ts = Node x (map (x <$) ts)

fmapTree :: (a -> b) -> Tree a -> Tree b
fmapTree f (Node x ts) = Node (f x) (map (fmapTree f) ts)

#ifdef __GLASGOW_HASKELL__
{-# NOINLINE [1] fmapTree #-}
{-# RULES
"fmapTree/coerce" fmapTree coerce = coerce
 #-}
#endif

instance Applicative Tree where
    pure x = Node x []
    Node f tfs <*> tx@(Node x txs) =
        Node (f x) (map (f <$>) txs ++ map (<*> tx) tfs)
    liftA2 f (Node x txs) ty@(Node y tys) =
        Node (f x y) (map (f x <$>) tys ++ map (\tx -> liftA2 f tx ty) txs)
    Node x txs <* ty@(Node _ tys) =
        Node x (map (x <$) tys ++ map (<* ty) txs)
    Node _ txs *> ty@(Node y tys) =
        Node y (tys ++ map (*> ty) txs)

instance Monad Tree where
    Node x ts >>= f = case f x of
        Node x' ts' -> Node x' (ts' ++ map (>>= f) ts)

-- | @since 0.5.11
instance MonadFix Tree where
  mfix = mfixTree

mfixTree :: (a -> Tree a) -> Tree a
mfixTree f
  | Node a children <- fix (f . rootLabel)
  = Node a (zipWith (\i _ -> mfixTree ((!! i) . subForest . f))
                    [0..] children)

-- | Traverses in pre-order.
instance Traversable Tree where
  traverse f = go
    where go (Node x ts) = liftA2 Node (f x) (traverse go ts)
  {-# INLINE traverse #-}

-- | Folds in pre-order.

-- See Note [Implemented Foldable Tree functions]
instance Foldable Tree where
    fold = foldMap id
    {-# INLINABLE fold #-}

    foldMap = foldMapDefault
    {-# INLINE foldMap #-}

    foldr f z = \t -> go t z  -- Use a lambda to allow inlining with two arguments
      where
        go (Node x ts) = f x . foldr (\t k -> go t . k) id ts
        -- This is equivalent to the following simpler definition, but has been found to optimize
        -- better in benchmarks:
        -- go (Node x ts) z' = f x (foldr go z' ts)
    {-# INLINE foldr #-}

    foldl' f = go
      where go !z (Node x ts) = foldl' go (f z x) ts
    {-# INLINE foldl' #-}

    foldr1 = foldrMap1 id

    foldl1 = foldlMap1 id

    null _ = False
    {-# INLINE null #-}

    elem = any . (==)
    {-# INLINABLE elem #-}

    maximum = foldlMap1' id max
    {-# INLINABLE maximum #-}

    minimum = foldlMap1' id min
    {-# INLINABLE minimum #-}

    sum = foldlMap1' id (+)
    {-# INLINABLE sum #-}

    product = foldlMap1' id (*)
    {-# INLINABLE product #-}

#if MIN_VERSION_base(4,18,0)
-- | Folds in pre-order.
--
-- @since 0.6.7

-- See Note [Implemented Foldable1 Tree functions]
instance Foldable1.Foldable1 Tree where
  foldMap1 f = go
    where
      -- We'd like to write
      --
      -- go (Node x (t : ts)) = f x <> Foldable1.foldMap1 go (t :| ts)
      --
      -- but foldMap1 for NonEmpty isn't very good, so we don't. See
      -- https://github.com/haskell/containers/pull/921#issuecomment-1410398618
      go (Node x []) = f x
      go (Node x (t : ts)) =
        f x <> Foldable1.foldrMap1 go (\t' z -> go t' <> z) (t :| ts)
  {-# INLINE foldMap1 #-}

  foldMap1' f = foldlMap1' f (\z x -> z <> f x)
  {-# INLINE foldMap1' #-}

  toNonEmpty (Node x ts) = x :| concatMap toList ts

  maximum = Foldable.maximum
  {-# INLINABLE maximum #-}

  minimum = Foldable.minimum
  {-# INLINABLE minimum #-}

  foldrMap1 = foldrMap1

  foldlMap1' = foldlMap1'

  foldlMap1 = foldlMap1
#endif

foldrMap1 :: (a -> b) -> (a -> b -> b) -> Tree a -> b
foldrMap1 f g = go
  where
    go (Node x [])     = f x
    go (Node x (t:ts)) = g x (foldrMap1NE go (\t' z -> foldr g z t') t ts)
{-# INLINE foldrMap1 #-}

-- This is foldrMap1 for Data.List.NonEmpty, but is not available before
-- base 4.18.
foldrMap1NE :: (a -> b) -> (a -> b -> b) -> a -> [a] -> b
foldrMap1NE f g = go
  where
    go x []      = f x
    go x (x':xs) = g x (go x' xs)
{-# INLINE foldrMap1NE #-}

foldlMap1' :: (a -> b) -> (b -> a -> b) -> Tree a -> b
foldlMap1' f g =  -- Use a lambda to allow inlining with two arguments
  \(Node x ts) -> foldl' (foldl' g) (f x) ts
{-# INLINE foldlMap1' #-}

foldlMap1 :: (a -> b) -> (b -> a -> b) -> Tree a -> b
foldlMap1 f g =  -- Use a lambda to allow inlining with two arguments
  \(Node x ts) -> foldl (foldl g) (f x) ts
{-# INLINE foldlMap1 #-}

instance NFData a => NFData (Tree a) where
    rnf (Node x ts) = rnf x `seq` rnf ts

-- | @since 0.8
instance NFData1 Tree where
    liftRnf rnfx = go
      where
      go (Node x ts) = rnfx x `seq` liftRnf go ts

-- | @since 0.5.10.1
instance MonadZip Tree where
  mzipWith f (Node a as) (Node b bs)
    = Node (f a b) (mzipWith (mzipWith f) as bs)

  munzip (Node (a, b) ts) = (Node a as, Node b bs)
    where (as, bs) = munzip (map munzip ts)

-- | 2-dimensional ASCII drawing of a tree.
--
-- ==== __Examples__
--
-- > putStr $ drawTree $ fmap show (Node 1 [Node 2 [], Node 3 []])
--
-- @
-- 1
-- |
-- +- 2
-- |
-- `- 3
-- @
--
drawTree :: Tree String -> String
drawTree  = unlines . draw

-- | 2-dimensional ASCII drawing of a forest.
--
-- ==== __Examples__
--
-- > putStr $ drawForest $ map (fmap show) [(Node 1 [Node 2 [], Node 3 []]), (Node 10 [Node 20 []])]
--
-- @
-- 1
-- |
-- +- 2
-- |
-- `- 3
--
-- 10
-- |
-- `- 20
-- @
--
drawForest :: [Tree String] -> String
drawForest  = unlines . map drawTree

draw :: Tree String -> [String]
draw (Node x ts0) = lines x ++ drawSubTrees ts0
  where
    drawSubTrees [] = []
    drawSubTrees [t] =
        "|" : shift "`- " "   " (draw t)
    drawSubTrees (t:ts) =
        "|" : shift "+- " "|  " (draw t) ++ drawSubTrees ts

    shift first other = zipWith (++) (first : repeat other)

-- | Returns the elements of a tree in pre-order.
--
-- @flatten == Data.Foldable.'toList'@
--
-- @
--
--   a
--  / \\    => [a,b,c]
-- b   c
-- @
--
-- ==== __Examples__
--
-- > flatten (Node 1 [Node 2 [], Node 3 []]) == [1,2,3]
flatten :: Tree a -> [a]
flatten = toList

-- | Returns the list of nodes at each level of the tree.
--
-- @
--
--   a
--  / \\    => [[a], [b,c]]
-- b   c
-- @
--
-- ==== __Examples__
--
-- > levels (Node 1 [Node 2 [], Node 3 []]) == [[1],[2,3]]
--
levels :: Tree a -> [[a]]
levels t =
    map (map rootLabel) $
        takeWhile (not . null) $
        iterate (concatMap subForest) [t]

-- | Fold a tree into a "summary" value.
--
-- For each node in the tree, apply @f@ to the @rootLabel@ and the result
-- of applying @f@ to each @subForest@.
--
-- This is also known as the catamorphism on trees.
--
-- ==== __Examples__
--
-- Sum the values in a tree:
--
-- > foldTree (\x xs -> sum (x:xs)) (Node 1 [Node 2 [], Node 3 []]) == 6
--
-- Find the maximum value in the tree:
--
-- > foldTree (\x xs -> maximum (x:xs)) (Node 1 [Node 2 [], Node 3 []]) == 3
--
-- Count the number of leaves in the tree:
--
-- > foldTree (\_ xs -> if null xs then 1 else sum xs) (Node 1 [Node 2 [], Node 3 []]) == 2
--
-- Find depth of the tree; i.e. the number of branches from the root of the tree to the furthest leaf:
--
-- > foldTree (\_ xs -> if null xs then 0 else 1 + maximum xs) (Node 1 [Node 2 [], Node 3 []]) == 1
--
-- You can even implement traverse using foldTree:
--
-- > traverse' f = foldTree (\x xs -> liftA2 Node (f x) (sequenceA xs))
--
--
-- @since 0.5.8
foldTree :: (a -> [b] -> b) -> Tree a -> b
foldTree f = go where
    go (Node x ts) = f x (map go ts)

-- | Build a (possibly infinite) tree from a seed value.
--
-- @unfoldTree f b@ constructs a tree by starting with the tree
-- @Node { rootLabel=b, subForest=[] }@ and repeatedly applying @f@ to each
-- 'rootLabel' value in the tree's leaves to generate its 'subForest'.
--
-- For a monadic version, see 'unfoldTreeM' (depth-first) and
-- 'unfoldTreeM_BF' (breadth-first).
--
-- ==== __Examples__
--
-- Construct the tree of @Integer@s where each node has two children:
-- @left = 2*x@ and @right = 2*x + 1@, where @x@ is the 'rootLabel' of the node.
-- Stop when the values exceed 7.
--
-- > let buildNode x = if 2*x + 1 > 7 then (x, []) else (x, [2*x, 2*x+1])
-- > putStr $ drawTree $ fmap show $ unfoldTree buildNode 1
--
-- @
--
-- 1
-- |
-- +- 2
-- |  |
-- |  +- 4
-- |  |
-- |  `- 5
-- |
-- `- 3
--    |
--    +- 6
--    |
--    `- 7
-- @
--
unfoldTree :: (b -> (a, [b])) -> b -> Tree a
unfoldTree f b = let (a, bs) = f b in Node a (unfoldForest f bs)

-- | Build a (possibly infinite) forest from a list of seed values.
--
-- @unfoldForest f seeds@ invokes 'unfoldTree' on each seed value.
--
-- For a monadic version, see 'unfoldForestM' (depth-first) and
-- 'unfoldForestM_BF' (breadth-first).
--
unfoldForest :: (b -> (a, [b])) -> [b] -> [Tree a]
unfoldForest f = map (unfoldTree f)

-- | Monadic tree builder, in depth-first order.
unfoldTreeM :: Monad m => (b -> m (a, [b])) -> b -> m (Tree a)
unfoldTreeM f b = do
    (a, bs) <- f b
    ts <- unfoldForestM f bs
    return (Node a ts)

-- | Monadic forest builder, in depth-first order.
unfoldForestM :: Monad m => (b -> m (a, [b])) -> [b] -> m ([Tree a])
unfoldForestM f = Prelude.mapM (unfoldTreeM f)

-- | Monadic tree builder, in breadth-first order.
--
-- See 'unfoldTree' for more info.
--
-- Implemented using an algorithm adapted from
-- /Breadth-First Numbering: Lessons from a Small Exercise in Algorithm Design/,
-- by Chris Okasaki, /ICFP'00/.
unfoldTreeM_BF :: Monad m => (b -> m (a, [b])) -> b -> m (Tree a)
unfoldTreeM_BF f b = liftM getElement $ unfoldForestQ f (singleton b)
  where
    getElement xs = case viewl xs of
        x :< _ -> x
        EmptyL -> error "unfoldTreeM_BF"

-- | Monadic forest builder, in breadth-first order.
--
-- See 'unfoldForest' for more info.
--
-- Implemented using an algorithm adapted from
-- /Breadth-First Numbering: Lessons from a Small Exercise in Algorithm Design/,
-- by Chris Okasaki, /ICFP'00/.
unfoldForestM_BF :: Monad m => (b -> m (a, [b])) -> [b] -> m ([Tree a])
unfoldForestM_BF f = liftM toList . unfoldForestQ f . fromList

-- Takes a sequence (queue) of seeds and produces a sequence (reversed queue) of
-- trees of the same length.
unfoldForestQ :: Monad m => (b -> m (a, [b])) -> Seq b -> m (Seq (Tree a))
unfoldForestQ f aQ = case viewl aQ of
    EmptyL -> return empty
    a :< aQ' -> do
        (b, as) <- f a
        tQ <- unfoldForestQ f (Prelude.foldl (|>) aQ' as)
        let (tQ', ts) = splitOnto [] as tQ
        return (Node b ts <| tQ')
  where
    splitOnto :: [a'] -> [b'] -> Seq a' -> (Seq a', [a'])
    splitOnto as [] q = (q, as)
    splitOnto as (_:bs) q = case viewr q of
        q' :> a -> splitOnto (a:as) bs q'
        EmptyR -> error "unfoldForestQ"

-- | \(O(n)\). The leaves of the tree in left-to-right order.
--
-- A leaf is a node with no children.
--
-- ==== __Examples__
--
-- >>> :{
-- leaves $
--   Node 1
--     [ Node 2
--         [ Node 4 []
--         , Node 5 []
--         ]
--     , Node 3
--         [ Node 6 []
--         ]
--     ]
-- :}
-- [4,5,6]
-- >>> leaves (Node "root" [])
-- ["root"]
--
-- @since 0.8
leaves :: Tree a -> [a]
#ifdef __GLASGOW_HASKELL__
leaves t = GHC.Exts.build $ \cons nil ->
  let go (Node x []) z = cons x z
      go (Node _ ts) z = foldr go z ts
  in go t nil
{-# INLINE leaves #-} -- Inline for list fusion
#else
leaves t =
  let go (Node x []) z = x:z
      go (Node _ ts) z = foldr go z ts
  in go t []
#endif

-- | \(O(n)\). The edges of the tree as parent-child pairs in pre-order.
--
-- A tree with \(n\) nodes has \(n-1\) edges.
--
-- ==== __Examples__
--
-- >>> :{
-- edges $
--   Node 1
--     [ Node 2
--         [ Node 4 []
--         , Node 5 []
--         ]
--     , Node 3
--         [ Node 6 []
--         ]
--     ]
-- :}
-- [(1,2),(2,4),(2,5),(1,3),(3,6)]
-- >>> edges (Node "root" [])
-- []
--
-- @since 0.8
edges :: Tree a -> [(a, a)]
#ifdef __GLASGOW_HASKELL__
edges (Node x0 ts0) = GHC.Exts.build $ \cons nil ->
  let go p = foldr (\(Node x ts) z -> cons (p, x) (go x z ts))
  in go x0 nil ts0
{-# INLINE edges #-} -- Inline for list fusion
#else
edges (Node x0 ts0) =
  let go p = foldr (\(Node x ts) z -> (p, x) : go x z ts)
  in go x0 [] ts0
#endif

-- | \(O(n)\). Labels on the paths from each node to the root.
--
-- ==== __Examples__
--
-- >>> :{
-- pathsToRoot $
--   Node 1
--     [ Node 2 []
--     , Node 3 []
--     ]
-- :}
-- Node {rootLabel = 1 :| [], subForest = [Node {rootLabel = 2 :| [1], subForest = []},Node {rootLabel = 3 :| [1], subForest = []}]}
-- >>> pathsToRoot (Node "root" [])
-- Node {rootLabel = "root" :| [], subForest = []}
--
-- @since 0.8
pathsToRoot :: Tree a -> Tree (NonEmpty a)
pathsToRoot = go []
  where
    go ps (Node x ts) = Node (x :| ps) (map (go (x:ps)) ts)

-- | Labels on the paths from the root to each node.
--
-- If the path orientation is not important, consider using 'pathsToRoot'
-- instead because it is more efficient.
--
-- ==== __Examples__
--
-- >>> :{
-- pathsFromRoot $
--   Node 1
--     [ Node 2 []
--     , Node 3 []
--     ]
-- :}
-- Node {rootLabel = 1 :| [], subForest = [Node {rootLabel = 1 :| [2], subForest = []},Node {rootLabel = 1 :| [3], subForest = []}]}
-- >>> pathsFromRoot (Node "root" [])
-- Node {rootLabel = "root" :| [], subForest = []}
--
-- @since 0.8

-- See Note [pathsFromRoot implementation]
pathsFromRoot :: Tree a -> Tree (NonEmpty a)
pathsFromRoot (Node x0 ts0) = Node (x0 :| []) (map (go (singletonBQ x0)) ts0)
  where
    go !q (Node x ts) = Node (toNonEmptyBQ q') (map (go q') ts)
      where
        !q' = snocBQ q x

-- An implementation of Chris Okasaki's banker's queue.
-- Invariant: length front >= length rear
data BQ a = BQ
  a -- head
  {-# UNPACK #-} !Word -- length front + length rear
  [a] -- front
  ![a] -- rear (reversed)

singletonBQ :: a -> BQ a
singletonBQ x = BQ x 0 [] []

snocBQ :: BQ a -> a -> BQ a
snocBQ (BQ x0 n f r) x
  | doReverse = BQ x0 (n+1) (f ++ reverse (x:r)) []
  | otherwise = BQ x0 (n+1) f (x:r)
  where
    doReverse = (n+2) .&. (n+1) == 0
    -- We reverse whenever the length of r would exceed that of f.
    -- This happens every time n+2 is a power of 2.

toNonEmptyBQ :: BQ a -> NonEmpty a
toNonEmptyBQ (BQ x0 _ f r) = case r of
  [] -> x0 :| f -- optimization, no need to rebuild f
  _ -> x0 :| (f ++ reverse r)

-- | A newtype over 'Tree' that folds and traverses in post-order.
--
-- @since 0.8
newtype PostOrder a = PostOrder { unPostOrder :: Tree a }
#ifdef __GLASGOW_HASKELL__
  deriving (Eq, Ord, Read, Show, Data, Generic, Generic1, Lift)
#else
  deriving (Eq, Ord, Read, Show)
#endif

instance Functor PostOrder where
#ifdef __GLASGOW_HASKELL__
  fmap = (coerce :: ((a -> b) -> Tree a -> Tree b)
                 -> (a -> b) -> PostOrder a -> PostOrder b)
         fmapTree
  (<$) = (coerce :: (b -> Tree a -> Tree b)
                 -> b -> PostOrder a -> PostOrder b)
         (<$)
#else
  fmap f = PostOrder . fmapTree f . unPostOrder
  (<$) x = PostOrder . (x <$) . unPostOrder
#endif

-- See Note [Implemented Foldable Tree functions]
instance Foldable PostOrder where
    fold = foldMap id
    {-# INLINABLE fold #-}

    foldMap = foldMapDefault
    {-# INLINE foldMap #-}

    foldr f z0 = \(PostOrder t) -> go t z0  -- Use a lambda to inline with two arguments
      where
        go (Node x ts) z = foldr go (f x z) ts
    {-# INLINE foldr #-}

    foldl' f z0 = \(PostOrder t) -> go z0 t  -- Use a lambda to inline with two arguments
      where
        go !z (Node x ts) =
          let !z' = foldl' go z ts
          in f z' x
    {-# INLINE foldl' #-}

    foldr1 = foldrMap1PostOrder id

    foldl1 = foldlMap1PostOrder id

    null _ = False
    {-# INLINE null #-}

    elem = any . (==)
    {-# INLINABLE elem #-}

    maximum = foldlMap1'PostOrder id max
    {-# INLINABLE maximum #-}

    minimum = foldlMap1'PostOrder id min
    {-# INLINABLE minimum #-}

    sum = foldlMap1'PostOrder id (+)
    {-# INLINABLE sum #-}

    product = foldlMap1'PostOrder id (*)
    {-# INLINABLE product #-}

instance Traversable PostOrder where
  traverse f = \(PostOrder t) -> PostOrder <$> go t
    where
      go (Node x ts) = liftA2 (flip Node) (traverse go ts) (f x)
  {-# INLINE traverse #-}

#if MIN_VERSION_base(4,18,0)
-- See Note [Implemented Foldable1 Tree functions]
instance Foldable1.Foldable1 PostOrder where
  foldMap1 f = \(PostOrder t) -> go t  -- Use a lambda to inline with one argument
    where
      go (Node x []) = f x
      go (Node x (t:ts)) =
        Foldable1.foldrMap1 go (\t' z' -> go t' <> z') (t :| ts) <> f x
  {-# INLINE foldMap1 #-}

  foldMap1' f = foldlMap1'PostOrder f (\z x -> z <> f x)
  {-# INLINE foldMap1' #-}

  toNonEmpty (PostOrder t0) = go t0 []
    where
      go (Node x []) z = x :| z
      go (Node x (t:ts)) z =
        go t (foldr (\t' z' -> foldr (:) z' (PostOrder t')) (x:z) ts)

  maximum = Foldable.maximum
  {-# INLINABLE maximum #-}

  minimum = Foldable.minimum
  {-# INLINABLE minimum #-}

  foldrMap1 = foldrMap1PostOrder

  foldlMap1' = foldlMap1'PostOrder

  foldlMap1 = foldlMap1PostOrder
#endif

foldrMap1PostOrder :: (a -> b) -> (a -> b -> b) -> PostOrder a -> b
foldrMap1PostOrder f g = \(PostOrder (Node x ts)) ->
  foldr (\t z -> foldr g z (PostOrder t)) (f x) ts
{-# INLINE foldrMap1PostOrder #-}

foldlMap1PostOrder :: (a -> b) -> (b -> a -> b) -> PostOrder a -> b
foldlMap1PostOrder f g = \(PostOrder t) -> go t
  where
    go (Node x []) = f x
    go (Node x (t:ts)) =
      g (foldl (\z t' -> foldl g z (PostOrder t')) (go t) ts) x
{-# INLINE foldlMap1PostOrder #-}

foldlMap1'PostOrder :: (a -> b) -> (b -> a -> b) -> PostOrder a -> b
foldlMap1'PostOrder f g = \(PostOrder t) -> go t
  where
    go (Node x []) = f x
    go (Node x (t:ts)) =
      let !z' = foldl' (\z t' -> foldl' g z (PostOrder t')) (go t) ts
      in g z' x
{-# INLINE foldlMap1'PostOrder #-}

--------------------------------------------------------------------------------

-- Note [Implemented Foldable Tree functions]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
-- Implemented:
--
-- foldMap, foldr, foldl': Basic functions.
-- fold, elem: Implemented same as the default definition, but INLINABLE to
-- allow specialization.
-- foldr1, foldl1, null, maximum, minimum: Implemented more efficiently than
-- defaults since trees are non-empty.
-- sum, product: Implemented as strict left folds. Defaults use the lazy foldMap
-- before base 4.15.1.
--
-- Not implemented:
--
-- foldMap', toList, length: Defaults perform well.
-- foldr', foldl: Unlikely to be used.

-- Note [Implemented Foldable1 Tree functions]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
-- Implemented:
--
-- foldMap, foldrMap1, foldlMap1': Basic functions
-- foldMap1': Implemented same as the default definition, but INLINABLE to
-- allow specialization.
-- toNonEmpty, foldlMap1: Implemented more efficiently than default.
-- maximum, minimum: Uses Foldable's implementation.
--
-- Not implemented:
--
-- fold1, head: Defaults perform well.
-- foldrMap1': Unlikely to be used.

-- Note [pathsFromRoot implementation]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- We use Okasaki's banker's queue for pathsFromRoot because it has some
-- desirable properties when the result is consumed lazily.
--
-- 1. Fully evaluating a node's NonEmpty takes O(d) time, where d is
--    the depth of the node. This is optimal.
-- 2. The elements in the NonEmpty are yielded lazily. Note that the worst case
--    time to yield an element is not O(1), i.e. it is only amortized O(1).
--    More than O(1) work is done when the next element requires forcing (++)
--    suspensions or reversing a rear list. For example, yielding the head has
--    to force O(log d) (++) and so takes O(log d) time.
-- 3. It builds up some beneficial sharing. It is not possible to share the
--    results since the lists have different ends, but we can share some
--    intermediate structures. Consider m sibling nodes at depth d. The front
--    list is shared between them in (front ++ rear1), (front ++ rear2), ...
--    (front + rearm). Forcing a prefix of front in one list can take arbitrary
--    amounts of time per element (total bounded by O(d)), but once it is
--    forced, front is memoized and doing the same for any of the siblings will
--    take O(1) per element.
--
-- Alternatives:
--
-- * Implement it like pathsToRoot and reverse the NonEmptys. This does satisfy
--   point 1 above. On 2 there's a trade-off, it costs a full O(d) to access the
--   head and O(1) per element after that. On 3 it compares poorly because there
--   is no sharing. Accessing the heads of m siblings will take O(dm) compared
--   to the current O(d + m).
-- * Use Okasaki's real-time queues. This would guarantee O(1) per element, but
--   has worse constant-factor overall and does not seem worth the trouble.
--
-- GHC base also uses a banker's queue for Data.List.inits. inits is similar
-- in nature to pathsFromRoot since a list is a tree where each node has one or
-- zero children.
