{-# LANGUAGE StandaloneDeriving, FlexibleInstances, MultiParamTypeClasses, DeriveAnyClass #-}

-- |Module `Containers.Pair` include type `Pair` and useful functions for work
--  with it.
--
--  `Pair a` is just pair as `(a, a)`.
module Containers.Pair (
    Pair (Pair),
    unPair,
    first,
    second,
    swap,
    toList,
    toZipList,
    fromList,
  ) where

import Control.Lens (Each)
import Control.Applicative (ZipList(..))

newtype Pair a = Pair { Pair a -> (a, a)
unPair :: (a, a) }
    deriving (Pair a -> Pair a -> Bool
(Pair a -> Pair a -> Bool)
-> (Pair a -> Pair a -> Bool) -> Eq (Pair a)
forall a. Eq a => Pair a -> Pair a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Pair a -> Pair a -> Bool
$c/= :: forall a. Eq a => Pair a -> Pair a -> Bool
== :: Pair a -> Pair a -> Bool
$c== :: forall a. Eq a => Pair a -> Pair a -> Bool
Eq, Eq (Pair a)
Eq (Pair a)
-> (Pair a -> Pair a -> Ordering)
-> (Pair a -> Pair a -> Bool)
-> (Pair a -> Pair a -> Bool)
-> (Pair a -> Pair a -> Bool)
-> (Pair a -> Pair a -> Bool)
-> (Pair a -> Pair a -> Pair a)
-> (Pair a -> Pair a -> Pair a)
-> Ord (Pair a)
Pair a -> Pair a -> Bool
Pair a -> Pair a -> Ordering
Pair a -> Pair a -> Pair a
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall a. Ord a => Eq (Pair a)
forall a. Ord a => Pair a -> Pair a -> Bool
forall a. Ord a => Pair a -> Pair a -> Ordering
forall a. Ord a => Pair a -> Pair a -> Pair a
min :: Pair a -> Pair a -> Pair a
$cmin :: forall a. Ord a => Pair a -> Pair a -> Pair a
max :: Pair a -> Pair a -> Pair a
$cmax :: forall a. Ord a => Pair a -> Pair a -> Pair a
>= :: Pair a -> Pair a -> Bool
$c>= :: forall a. Ord a => Pair a -> Pair a -> Bool
> :: Pair a -> Pair a -> Bool
$c> :: forall a. Ord a => Pair a -> Pair a -> Bool
<= :: Pair a -> Pair a -> Bool
$c<= :: forall a. Ord a => Pair a -> Pair a -> Bool
< :: Pair a -> Pair a -> Bool
$c< :: forall a. Ord a => Pair a -> Pair a -> Bool
compare :: Pair a -> Pair a -> Ordering
$ccompare :: forall a. Ord a => Pair a -> Pair a -> Ordering
$cp1Ord :: forall a. Ord a => Eq (Pair a)
Ord)

instance Functor Pair where
    fmap :: (a -> b) -> Pair a -> Pair b
fmap a -> b
f (Pair (a
x, a
y)) = (b, b) -> Pair b
forall a. (a, a) -> Pair a
Pair (a -> b
f a
x, a -> b
f a
y)

instance Applicative Pair where
    pure :: a -> Pair a
pure a
x = (a, a) -> Pair a
forall a. (a, a) -> Pair a
Pair (a
x, a
x)
    (Pair (a -> b
f, a -> b
g)) <*> :: Pair (a -> b) -> Pair a -> Pair b
<*> (Pair (a
x, a
y)) = (b, b) -> Pair b
forall a. (a, a) -> Pair a
Pair (a -> b
f a
x, a -> b
g a
y)

instance Foldable Pair where
    foldr :: (a -> b -> b) -> b -> Pair a -> b
foldr a -> b -> b
f b
z = (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr a -> b -> b
f b
z ([a] -> b) -> (Pair a -> [a]) -> Pair a -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Pair a -> [a]
forall a. Pair a -> [a]
toList

instance Traversable Pair where
    sequenceA :: Pair (f a) -> f (Pair a)
sequenceA (Pair (f a
f, f a
g)) = (a, a) -> Pair a
forall a. (a, a) -> Pair a
Pair ((a, a) -> Pair a) -> f (a, a) -> f (Pair a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((,) (a -> a -> (a, a)) -> f a -> f (a -> (a, a))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> f a
f f (a -> (a, a)) -> f a -> f (a, a)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> f a
g)

deriving instance Each (Pair a) (Pair b) a b

first :: Pair a -> a
first :: Pair a -> a
first (Pair (a
x, a
_)) = a
x

second :: Pair a -> a
second :: Pair a -> a
second (Pair (a
_, a
y)) = a
y

swap :: Pair a -> Pair a
swap :: Pair a -> Pair a
swap (Pair (a
x, a
y)) = (a, a) -> Pair a
forall a. (a, a) -> Pair a
Pair (a
y, a
x)

toList :: Pair a -> [a]
toList :: Pair a -> [a]
toList (Pair (a
x, a
y)) = [a
x, a
y]

toZipList :: Pair a -> ZipList a
toZipList :: Pair a -> ZipList a
toZipList (Pair (a
x, a
y)) = [a] -> ZipList a
forall a. [a] -> ZipList a
ZipList [a
x, a
y]

fromList :: MonadFail m => [a] -> m (Pair a)
fromList :: [a] -> m (Pair a)
fromList [a
x, a
y] = Pair a -> m (Pair a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Pair a -> m (Pair a)) -> Pair a -> m (Pair a)
forall a b. (a -> b) -> a -> b
$ (a, a) -> Pair a
forall a. (a, a) -> Pair a
Pair (a
x, a
y)
fromList [a]
_ = String -> m (Pair a)
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Input list must contain just 2 elements"