{-# LANGUAGE Rank2Types #-}

module Data.TrieMap.CPair where

newtype CPair a b = CP (forall r . (a -> b -> r) -> r)

pairFromC :: CPair a b -> (a, b)
pairFromC (CP k) = k (,)

pairToC :: (a, b) -> CPair a b
pairToC p = CP (\ k -> uncurry k p)

instance Functor (CPair a) where
	fmap f (CP k) = CP (\ g -> k (\ x -> g x . f))

on1st :: (a -> b) -> CPair a c -> CPair b c
on1st f (CP k) = CP (\ g -> k (g . f))

on2nd :: (b -> c) -> CPair a b -> CPair a c
on2nd f (CP k) = CP (\ g -> k (\ x -> g x . f))

cP :: a -> b -> CPair a b
x `cP` y = CP (\ k -> k x y)

cpFst :: CPair a b -> a
cpFst = cpUncurry const

cpSnd :: CPair a b -> b
cpSnd = cpUncurry (flip const)

cpUncurry :: (a -> b -> r) -> CPair a b -> r
cpUncurry f (CP k) = k f

cpCurry :: (CPair a b -> r) -> a -> b -> r
cpCurry f a b = f (a `cP` b)