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

    goL acc Tip = acc
    goL acc (Bin _ maxV l r) = f (goR (goL acc l) r) maxV
    
    goR acc Tip = acc
    goR acc (Bin _ minV l r) = goR (goL (f acc minV) l) r

-- | /O(n)/. Fold the keys and values in the map using the given right-associative
-- binary operator, such that
-- @'foldrWithKey' f z == 'Prelude.foldr' ('uncurry' f) z . 'toAscList'@.
--
-- For example,
--
-- > keys map = foldrWithKey (\k x ks -> k:ks) [] map
--
-- > let f k a result = result ++ "(" ++ (show k) ++ ":" ++ a ++ ")"
-- > foldrWithKey f "Map: " (fromList [(5,"a"), (3,"b")]) == "Map: (5:a)(3:b)"

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

    goL acc Tip = acc
    goL acc (Bin _ maxV l r) = f (goR (goL acc l) r) maxV
    
    goR acc Tip = acc
    goR acc (Bin _ minV l r) = goR (goL (f acc minV) l) r

-- | /O(n)/. Fold the keys and values in the map using the given right-associative
-- binary operator, such that
-- @'foldrWithKey' f z == 'Prelude.foldr' ('uncurry' f) z . 'toAscList'@.
--
-- For example,
--
-- > keys map = foldrWithKey (\k x ks -> k:ks) [] map
--
-- > let f k a result = result ++ "(" ++ (show k) ++ ":" ++ a ++ ")"
-- > foldrWithKey f "Map: " (fromList [(5,"a"), (3,"b")]) == "Map: (5:a)(3:b)"

foldl f z = start
  where
    start (IntMap (WordMap Empty)) = z
    start (IntMap (WordMap (NonEmpty _ minV Tip))) = f z minV
    start (IntMap (WordMap (NonEmpty min minV (Bin max maxV l r))))
        | w2i (xor min max) < 0 = goL (f (f (goR z r) maxV) minV) l
        | otherwise = f (goR (goL (f z minV) l) r) maxV

    goL acc Tip = acc
    goL acc (Bin _ maxV l r) = f (goR (goL acc l) r) maxV
    
    goR acc Tip = acc
    goR acc (Bin _ minV l r) = goR (goL (f acc minV) l) r

-- | /O(n)/. Fold the keys and values in the map using the given right-associative
-- binary operator, such that
-- @'foldrWithKey' f z == 'Prelude.foldr' ('uncurry' f) z . 'toAscList'@.
--
-- For example,
--
-- > keys map = foldrWithKey (\k x ks -> k:ks) [] map
--
-- > let f k a result = result ++ "(" ++ (show k) ++ ":" ++ a ++ ")"
-- > foldrWithKey f "Map: " (fromList [(5,"a"), (3,"b")]) == "Map: (5:a)(3:b)"
