foldlWithKey :: (a -> Key -> b -> a) -> a -> IntMap b -> a
foldlWithKey f z = start
  where
    start (IntMap (WordMap Empty)) = z
    start (IntMap (WordMap (NonEmpty min minV Tip))) = f' z min minV
    start (IntMap (WordMap (NonEmpty min minV (Bin max maxV l r))))
        | w2i (xor min max) < 0 = goL (f' (f' (goR z r) max maxV) min minV) l
        | otherwise = f' (goR (goL (f' z min minV) l) r) max maxV

    goL acc Tip = acc
    goL acc (Bin max maxV l r) = f' (goR (goL acc l) r) max maxV
    
    goR acc Tip = acc
    goR acc (Bin min minV l r) = goR (goL (f' acc min minV) l) r
    
    f' a k b = f a (w2i k) b

-- | /O(n)/. Fold the keys and values in the map using the given monoid, such that
--
-- @'foldMapWithKey' f = 'Prelude.fold' . 'mapWithKey' f@
--
-- This can be an asymptotically faster than 'foldrWithKey' or 'foldlWithKey' for some monoids.
foldlWithKey :: (a -> Key -> b -> a) -> a -> IntMap b -> a
foldlWithKey f z = start
  where
    start (IntMap (WordMap Empty)) = z
    start (IntMap (WordMap (NonEmpty min minV Tip))) = f' z min minV
    start (IntMap (WordMap (NonEmpty min minV (Bin max maxV l r))))
        | w2i (xor min max) < 0 = goL (f' (f' (goR z r) max maxV) min minV) l
        | otherwise = f' (goR (goL (f' z min minV) l) r) max maxV

    goL acc Tip = acc
    goL acc (Bin max maxV l r) = f' (goR (goL acc l) r) max maxV
    
    goR acc Tip = acc
    goR acc (Bin min minV l r) = goR (goL (f' acc min minV) l) r
    
    f' a k b = f a (w2i k) b

-- | /O(n)/. Fold the keys and values in the map using the given monoid, such that
--
-- @'foldMapWithKey' f = 'Prelude.fold' . 'mapWithKey' f@
--
-- This can be an asymptotically faster than 'foldrWithKey' or 'foldlWithKey' for some monoids.
foldlWithKey f z = start
  where
    start (IntMap (WordMap Empty)) = z
    start (IntMap (WordMap (NonEmpty min minV Tip))) = f' z min minV
    start (IntMap (WordMap (NonEmpty min minV (Bin max maxV l r))))
        | w2i (xor min max) < 0 = goL (f' (f' (goR z r) max maxV) min minV) l
        | otherwise = f' (goR (goL (f' z min minV) l) r) max maxV

    goL acc Tip = acc
    goL acc (Bin max maxV l r) = f' (goR (goL acc l) r) max maxV
    
    goR acc Tip = acc
    goR acc (Bin min minV l r) = goR (goL (f' acc min minV) l) r
    
    f' a k b = f a (w2i k) b

-- | /O(n)/. Fold the keys and values in the map using the given monoid, such that
--
-- @'foldMapWithKey' f = 'Prelude.fold' . 'mapWithKey' f@
--
-- This can be an asymptotically faster than 'foldrWithKey' or 'foldlWithKey' for some monoids.