content: {-
    Copyright (c) Meta Platforms, Inc. and affiliates.
    All rights reserved.
  
    This source code is licensed under the BSD-style license found in the
    LICENSE file in the root directory of this source tree.
  -}
  
  {-# LANGUAGE PolyKinds #-}
  module Util.List.HigherOrder
    ( fold2
    , map2
    , mapMaybe2
    , concatMap2
    , traverse2, traverse2_
    ) where
  
  import Data.Foldable
  
  -- | Efficiently right fold over two lists in sequence that have different
  -- parameter types
  fold2 :: (forall (z :: k). t z -> b -> b) -> b -> [t x] -> [t y] -> b
  fold2 f b xs ys = foldr f (foldr f b ys) xs
  
  -- | Efficiently map a normalizing function over two lists with different type
  -- parameters
  map2 :: (forall (z :: k). t z -> b) -> [t x] -> [t y] -> [b]
  map2 f xs ys = foldr ((:) . f) (map f ys) xs
  
  -- | Like map2, but filter out Nothings
  mapMaybe2 :: (forall (z :: k). t z -> Maybe b) -> [t x] -> [t y] -> [b]
  mapMaybe2 f = fold2 (maybe id (:) . f) []
  
  concatMap2 :: (forall (z :: k). t z -> [b]) -> [t x] -> [t y] -> [b]
  concatMap2 f xs ys = concat $ map2 f xs ys
  
  traverse2
    :: Applicative f
    => (forall (z :: k). t z -> f a)
    -> [t x]
    -> [t y]
    -> f [a]
  traverse2 f (x:xs) ys = (:) <$> f x <*> traverse2 f xs ys
  traverse2 f [] ys = traverse f ys
  
  traverse2_
    :: Applicative f
    => (forall (z :: k). t z -> f ())
    -> [t x]
    -> [t y]
    -> f ()
  traverse2_ f (x:xs) ys = f x *> traverse2_ f xs ys
  traverse2_ f [] ys = traverse_ f ys
  