-- | An incomplete implementation of an extension of the 'Functor' and
-- 'Traversable' concepts to three type arguments.  I've implemented
-- enough for our purposes here.
module Data.Origami.Internal.Trifunctor(
    Trifunctor(..),
    Tritraversable(..)
) where

import Control.Monad(liftM3)

-- | Extends the 'Functor' concept to three type arguments.  (Note: we
-- are missing analogies to the functions 'first' and 'second' found
-- in "Data.Bifunctor".)
class Trifunctor f where
    -- | Maps over all three arguments simultaneously
    trimap :: (a -> a') -> (b -> b') -> (c -> c') -> f a b c -> f a' b' c'

instance Trifunctor (,,) where
    trimap fa fb fc (a, b, c) = (fa a, fb b, fc c)

-- | Extends the 'Traversable' concept to three type arguments.
-- (Note: we are missing analogies to the functions 'bitraverse',
-- 'bisequenceA' and 'bimapM' found in "Data.Bitraversable".)
class Tritraversable t where

    -- | Sequences all the actions in the structure, building a new
    -- structure with the same shape using the results of the actions.
    trisequence :: Monad m => t (m a) (m b) (m c) -> m (t a b c)

instance Tritraversable (,,) where
    trisequence (ma, mb, mc) = liftM3 (,,) ma mb mc