{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE Safe #-}
{-# LANGUAGE TypeOperators #-}
{-|
Module: Control.Natural
Copyright: (C) 2015 The University of Kansas
License: BSD-style (see the file LICENSE)
Maintainer: Andy Gill
Stability: Experimental
A data type and class for natural transformations.
-}
module Control.Natural
( -- * Type Synonym for a Natural Transformation
type (~>)
-- * Newtype for a Natural Transformation
, (:~>)(..)
-- * Class for Natural Transformations
, Transformation(..)
) where
import qualified Control.Category as C (Category(..))
#if !(MIN_VERSION_base(4,8,0))
import Data.Monoid (Monoid(..))
#endif
#if MIN_VERSION_base(4,9,0)
import Data.Semigroup (Semigroup(..))
#endif
import Data.Typeable
---------------------------------------------------------------------------
-- Naming of ~>, :~> and $$ are taken (with permission) from Edward Kmett's @indexed@ package.
---------------------------------------------------------------------------
infixr 0 ~>
-- | A natural transformation from @f@ to @g@.
type f ~> g = forall x. f x -> g x
infixr 0 :~>, $$
-- | A natural transformation suitable for storing in a container.
newtype f :~> g = Nat { ($$) :: f ~> g }
deriving Typeable
instance C.Category (:~>) where
id = Nat id
Nat f . Nat g = Nat (f . g)
#if MIN_VERSION_base(4,9,0)
instance f ~ g => Semigroup (f :~> g) where
Nat f <> Nat g = Nat (f . g)
#endif
instance f ~ g => Monoid (f :~> g) where
mempty = Nat id
mappend (Nat f) (Nat g) = Nat (f . g)
infix 0 #
-- | A (natural) transformation is inside @t@, and contains @f@ and @g@
-- (typically 'Functor's).
--
-- The order of arguments allows the use of @GeneralizedNewtypeDeriving@ to wrap
-- a ':~>', but maintain the 'Transformation' constraint. Thus, @#@ can be used
-- on abstract data types.
class Transformation f g t | t -> f g where
-- | The invocation method for a natural transformation.
(#) :: t -> f a -> g a
instance Transformation f g (f :~> g) where
Nat f # g = f g