```{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE NoMonoPatBinds #-}

-- | Constructor-destructor isomorphisms for some common datatypes.
module Data.Iso.Common (

-- * @()@
unit,

-- * @(,)@
tup,

-- * @(,,)@
tup3,

-- * @Maybe a@
nothing, just, maybe,

-- * @[a]@
nil, cons,

-- * @Either a b@
left, right, either,

-- * @Bool@
false, true, bool

) where

import Prelude hiding (id, (.), maybe, either)
import Control.Category

import Data.Iso.Core
import Data.Iso.TH

import Data.Semigroup

unit :: Iso t (() :- t)
unit = Iso f g
where
f       t  = Just (() :- t)
g (_ :- t) = Just t

tup :: Iso (a :- b :- t) ((a, b) :- t)
tup = Iso f g
where
f (a :- b :- t) = Just ((a, b) :- t)
g ((a, b) :- t) = Just (a :- b :- t)

tup3 :: Iso (a :- b :- c :- t) ((a, b, c) :- t)
tup3 = Iso f g
where
f (a :- b :- c :- t) = Just ((a, b, c) :- t)
g ((a, b, c) :- t) = Just (a :- b :- c :- t)

nothing :: Iso t (Maybe a :- t)
just    :: Iso (a :- t) (Maybe a :- t)
(nothing, just) = \$(deriveIsos ''Maybe)

maybe :: Iso t (a :- t) -> Iso t (Maybe a :- t)
maybe el = just . el <> nothing

nil :: Iso t ([a] :- t)
nil = Iso f g
where
f        t  = Just ([] :- t)
g ([] :- t) = Just t
g _         = Nothing

cons :: Iso (a :- [a] :- t) ([a] :- t)
cons = Iso f g
where
f (x :- xs  :- t) = Just ((x : xs) :- t)
g ((x : xs) :- t) = Just (x :- xs :- t)
g _               = Nothing

left  :: Iso (a :- t) (Either a b :- t)
right :: Iso (b :- t) (Either a b :- t)
(left, right) = \$(deriveIsos ''Either)

either :: Iso t1 (a :- t2) -> Iso t1 (b :- t2) -> Iso t1 (Either a b :- t2)
either f g = left . f <> right . g

false :: Iso t (Bool :- t)
true  :: Iso t (Bool :- t)
(false, true) = \$(deriveIsos ''Bool)

bool  :: Iso t (Bool :- t)
bool = false <> true
```