module Data.Church.Pair
( Pair(Pair)
, mkPair
, pair
) where
import Data.Bifunctor (Bifunctor (bimap), second)
import Data.Semigroup (Semigroup ((<>), stimes))
import Data.Functor.Classes (Eq2 (liftEq2), Eq1 (liftEq), Ord2 (liftCompare2),
Ord1 (liftCompare), eq2, compare2)
newtype Pair a b = Pair { runPair :: forall r. (a -> b -> r) -> r }
instance Bifunctor Pair where
bimap fx fy (Pair p) = Pair $ \r -> p $ \x y -> r (fx x) (fy y)
instance Functor (Pair a) where
fmap = second
instance Eq2 Pair where
liftEq2 f1 f2 (Pair px) (Pair py) = px $ \x1 x2 -> py $ \y1 y2 ->
f1 x1 y1 && f2 x2 y2
instance Ord2 Pair where
liftCompare2 f1 f2 (Pair px) (Pair py) = px $ \x1 x2 -> py $ \y1 y2 ->
case f1 x1 y1 of
EQ -> f2 x2 y2
oo -> oo
instance Eq a => Eq1 (Pair a) where
liftEq = liftEq2 (==)
instance Ord a => Ord1 (Pair a) where
liftCompare = liftCompare2 compare
instance (Eq a, Eq b) => Eq (Pair a b) where
(==) = eq2
instance (Ord a, Ord b) => Ord (Pair a b) where
compare = compare2
instance (Semigroup a, Semigroup b) => Semigroup (Pair a b) where
(<>) = liftMappend2 (<>) (<>)
stimes n (Pair p) = Pair $ \r -> p $ \x y -> r (stimes n x) (stimes n y)
instance (Monoid a, Monoid b) => Monoid (Pair a b) where
mempty = mkPair mempty mempty
mappend = liftMappend2 mappend mappend
instance Monoid a => Applicative (Pair a) where
pure = mkPair mempty
Pair pf <*> Pair px = Pair $ \r -> pf $ \u f -> px $ \v x ->
r (mappend u v) (f x)
instance Foldable (Pair a) where
foldr f z (Pair p) = p $ \_ y -> f y z
foldMap f (Pair p) = p $ \_ y -> f y
instance Traversable (Pair a) where
traverse f (Pair p) = p $ \x y -> mkPair x <$> f y
instance Monoid a => Monad (Pair a) where
return = pure
(Pair p) >>= k = Pair $ \r -> p $ \u a -> runPair (k a) $ r . mappend u
liftMappend2 :: (a -> a -> a)
-> (b -> b -> b)
-> (Pair a b -> Pair a b -> Pair a b)
liftMappend2 f1 f2 (Pair px) (Pair py) = Pair $ \r -> px $ \x1 x2 -> py $ \y1 y2 ->
r (f1 x1 y1) (f2 x2 y2)
pair :: (a -> b -> r) -> Pair a b -> r
pair = flip runPair
mkPair :: a -> b -> Pair a b
mkPair x y = Pair $ \r -> r x y