-- | -- Module: NetSpider.Pair -- Description: Swap-insensitive two-element homogeneous tuple -- Maintainer: Toshio Ito -- -- module NetSpider.Pair ( Pair(..), sortPair ) where import Control.Applicative (Applicative(..)) import Data.Foldable (Foldable(..)) import Data.Hashable (Hashable(hashWithSalt)) import Data.Traversable (Traversable(..)) -- | 'Pair' is a two-element tuple of the same type that is -- insensitive to swapping. 'Eq', 'Ord' and 'Hashable' instances treat -- 'Pair's with swapped elements as equivalent. newtype Pair a = Pair { unPair :: (a,a) } deriving (Show) instance Eq a => Eq (Pair a) where (Pair (al, ar)) == (Pair (bl, br)) = (al == bl && ar == br) || (al == br && ar == bl) instance Ord a => Ord (Pair a) where compare l r = compare (unPair $ sortPair l) (unPair $ sortPair r) instance (Ord a, Hashable a) => Hashable (Pair a) where hashWithSalt s p = hashWithSalt s $ unPair $ sortPair p instance Functor Pair where fmap f (Pair (l,r)) = Pair (f l, f r) instance Applicative Pair where pure a = Pair (a,a) (Pair (fl,fr)) <*> (Pair (al,ar)) = Pair (fl al, fr ar) instance Foldable Pair where foldr f start (Pair (l,r)) = foldr f start [l,r] instance Traversable Pair where traverse f (Pair (l,r)) = fmap Pair $ (,) <$> (f l) <*> (f r) -- | Sort the elements in the 'Pair'. sortPair :: Ord a => Pair a -> Pair a sortPair p@(Pair (l,r)) = if l <= r then p else Pair (r,l)