{-# LANGUAGE CPP #-}
{-# LANGUAGE Trustworthy #-}
module Data.Crosswalk (
Crosswalk (..),
Bicrosswalk (..),
) where
import Control.Applicative (pure, (<$>))
import Data.Bifoldable (Bifoldable (..))
import Data.Bifunctor (Bifunctor (..))
import Data.Foldable (Foldable (..))
import Data.Functor.Compose (Compose (..))
import Data.Functor.Identity (Identity (..))
import Data.Vector.Generic (Vector)
import Prelude (Either (..), Functor (fmap), Maybe (..), id, (.))
import qualified Data.Sequence as Seq
import qualified Data.Vector as V
import qualified Data.Vector.Generic as VG
import Data.Align
import Data.These
class (Functor t, Foldable t) => Crosswalk t where
crosswalk :: (Align f) => (a -> f b) -> t a -> f (t b)
crosswalk f = sequenceL . fmap f
sequenceL :: (Align f) => t (f a) -> f (t a)
sequenceL = crosswalk id
#if __GLASGOW_HASKELL__ >= 707
{-# MINIMAL crosswalk | sequenceL #-}
#endif
instance Crosswalk Identity where
crosswalk f (Identity a) = fmap Identity (f a)
instance Crosswalk Maybe where
crosswalk _ Nothing = nil
crosswalk f (Just a) = Just <$> f a
instance Crosswalk [] where
crosswalk _ [] = nil
crosswalk f (x:xs) = alignWith cons (f x) (crosswalk f xs)
where cons = these pure id (:)
instance Crosswalk Seq.Seq where
crosswalk f = foldr (alignWith cons . f) nil where
cons = these Seq.singleton id (Seq.<|)
instance Crosswalk (These a) where
crosswalk _ (This _) = nil
crosswalk f (That x) = That <$> f x
crosswalk f (These a x) = These a <$> f x
crosswalkVector :: (Vector v a, Vector v b, Align f)
=> (a -> f b) -> v a -> f (v b)
crosswalkVector f = fmap VG.fromList . VG.foldr (alignWith cons . f) nil where
cons = these pure id (:)
instance Crosswalk V.Vector where
crosswalk = crosswalkVector
instance Crosswalk ((,) a) where
crosswalk fun (a, x) = fmap ((,) a) (fun x)
instance (Crosswalk f, Crosswalk g) => Crosswalk (Compose f g) where
crosswalk f
= fmap Compose
. crosswalk (crosswalk f)
. getCompose
class (Bifunctor t, Bifoldable t) => Bicrosswalk t where
bicrosswalk :: (Align f) => (a -> f c) -> (b -> f d) -> t a b -> f (t c d)
bicrosswalk f g = bisequenceL . bimap f g
bisequenceL :: (Align f) => t (f a) (f b) -> f (t a b)
bisequenceL = bicrosswalk id id
#if __GLASGOW_HASKELL__ >= 707
{-# MINIMAL bicrosswalk | bisequenceL #-}
#endif
instance Bicrosswalk Either where
bicrosswalk f _ (Left x) = Left <$> f x
bicrosswalk _ g (Right x) = Right <$> g x
instance Bicrosswalk These where
bicrosswalk f _ (This x) = This <$> f x
bicrosswalk _ g (That x) = That <$> g x
bicrosswalk f g (These x y) = align (f x) (g y)