{-# LANGUAGE TypeFamilies, FlexibleContexts, FlexibleInstances #-}
{-# OPTIONS_GHC -fenable-rewrite-rules #-}
----------------------------------------------------------------------
-- |
-- Module : Data.Functor.Corepresentable
-- Copyright : (c) Edward Kmett 2011
-- License : BSD3
--
-- Maintainer : ekmett@gmail.com
-- Stability : experimental
--
-- Representable contravariant endofunctors over the category of Haskell
-- types are isomorphic to @(_ -> r)@ and resemble mappings to a
-- fixed range.
----------------------------------------------------------------------
module Data.Functor.Corepresentable
(
-- * Values
Value
-- * Contravariant Keyed
, Valued(..)
-- * Contravariant Indexed
, Coindexed(..)
-- * Representable Contravariant Functors
, Corepresentable(..)
-- * Default definitions
, contramapDefault
, contramapWithValueDefault
) where
import Control.Monad.Reader
import Data.Functor.Contravariant
import Data.Functor.Product
import Data.Functor.Coproduct
import Prelude hiding (lookup)
type family Value (f :: * -> *)
-- | Dual to 'Keyed'.
class Contravariant f => Valued f where
contramapWithValue :: (b -> Either a (Value f)) -> f a -> f b
-- | Dual to 'Indexed'.
class Coindexed f where
coindex :: f a -> a -> Value f
-- | A 'Functor' @f@ is 'Corepresentable' if 'corep' and 'coindex' witness an isomorphism to @(_ -> Value f)@.
--
-- > tabulate . index = id
-- > index . tabulate = id
-- > tabulate . return f = return f
class (Coindexed f, Valued f) => Corepresentable f where
-- | > contramap f (corep g) = corep (g . f)
corep :: (a -> Value f) -> f a
{-# RULES
"corep/coindex" forall t. corep (coindex t) = t
#-}
-- * Default definitions
contramapDefault :: Corepresentable f => (a -> b) -> f b -> f a
contramapDefault f = corep . (. f) . coindex
contramapWithValueDefault :: Corepresentable f => (b -> Either a (Value f)) -> f a -> f b
contramapWithValueDefault f p = corep $ either (coindex p) id . f
-- * Dual arrows
type instance Value (Op r) = r
instance Valued (Op r) where
contramapWithValue = contramapWithValueDefault
instance Coindexed (Op r) where
coindex = getOp
instance Corepresentable (Op r) where
corep = Op
-- * Predicates
type instance Value Predicate = Bool
instance Valued Predicate where
contramapWithValue = contramapWithValueDefault
instance Coindexed Predicate where
coindex = getPredicate
instance Corepresentable Predicate where
corep = Predicate
-- * Products
type instance Value (Product f g) = (Value f, Value g)
instance (Valued f, Valued g) => Valued (Product f g) where
-- contramapWithValue :: (b -> Either a (Value f)) -> f a -> f b
contramapWithValue h (Pair f g) = Pair
(contramapWithValue (fmap fst . h) f)
(contramapWithValue (fmap snd . h) g)
-- (contramapWithValue (either id snd . h) g)
-- (either g snd . h)
instance (Coindexed f, Coindexed g) => Coindexed (Product f g) where
coindex (Pair f g) a = (coindex f a, coindex g a)
instance (Corepresentable f, Corepresentable g) => Corepresentable (Product f g) where
corep f = Pair (corep (fst . f)) (corep (snd . f))
-- * Coproducts
type instance Value (Coproduct f g) = Either (Value f) (Value g)
instance (Coindexed f, Coindexed g) => Coindexed (Coproduct f g) where
coindex (Coproduct (Left f)) a = Left $ coindex f a
coindex (Coproduct (Right g)) a = Right $ coindex g a