foldMapWithKey :: Monoid m => (Key -> a -> m) -> IntMap a -> m
foldMapWithKey f = start
  where
    start (IntMap (WordMap Empty)) = mempty
    start (IntMap (WordMap (NonEmpty min minV Tip))) = f (w2i min) minV
    start (IntMap (WordMap (NonEmpty min minV (Bin max maxV l r))))
        | w2i (xor min max) < 0 = goR r `mappend` f (w2i max) maxV `mappend` f (w2i min) minV `mappend` goL l
        | otherwise = f (w2i min) minV `mappend` goL l `mappend` goR r `mappend` f (w2i max) maxV
    
    goL Tip = mempty
    goL (Bin max maxV l r) = goL l `mappend` goR r `mappend` f (w2i max) maxV
    
    goR Tip = mempty
    goR (Bin min minV l r) = f (w2i min) minV `mappend` goL l `mappend` goR r

-- | /O(n)/. A strict version of 'foldr'. Each application of the operator is
-- evaluated before using the result in the next application. This
-- function is strict in the starting value.

foldMapWithKey :: Monoid m => (Key -> a -> m) -> IntMap a -> m
foldMapWithKey f = start
  where
    start (IntMap (WordMap Empty)) = mempty
    start (IntMap (WordMap (NonEmpty min minV Tip))) = f (w2i min) minV
    start (IntMap (WordMap (NonEmpty min minV (Bin max maxV l r))))
        | w2i (xor min max) < 0 = goR r `mappend` f (w2i max) maxV `mappend` f (w2i min) minV `mappend` goL l
        | otherwise = f (w2i min) minV `mappend` goL l `mappend` goR r `mappend` f (w2i max) maxV
    
    goL Tip = mempty
    goL (Bin max maxV l r) = goL l `mappend` goR r `mappend` f (w2i max) maxV
    
    goR Tip = mempty
    goR (Bin min minV l r) = f (w2i min) minV `mappend` goL l `mappend` goR r

-- | /O(n)/. A strict version of 'foldr'. Each application of the operator is
-- evaluated before using the result in the next application. This
-- function is strict in the starting value.

foldMapWithKey f = start
  where
    start (IntMap (WordMap Empty)) = mempty
    start (IntMap (WordMap (NonEmpty min minV Tip))) = f (w2i min) minV
    start (IntMap (WordMap (NonEmpty min minV (Bin max maxV l r))))
        | w2i (xor min max) < 0 = goR r `mappend` f (w2i max) maxV `mappend` f (w2i min) minV `mappend` goL l
        | otherwise = f (w2i min) minV `mappend` goL l `mappend` goR r `mappend` f (w2i max) maxV
    
    goL Tip = mempty
    goL (Bin max maxV l r) = goL l `mappend` goR r `mappend` f (w2i max) maxV
    
    goR Tip = mempty
    goR (Bin min minV l r) = f (w2i min) minV `mappend` goL l `mappend` goR r

-- | /O(n)/. A strict version of 'foldr'. Each application of the operator is
-- evaluated before using the result in the next application. This
-- function is strict in the starting value.
