{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies #-} ----------------------------------------------------------------------------- -- | -- Module : Data.Profunctor.Rep -- Copyright : (C) 2011-2012 Edward Kmett, -- License : BSD-style (see the file LICENSE) -- -- Maintainer : Edward Kmett -- Stability : provisional -- Portability : MPTCs -- ---------------------------------------------------------------------------- module Data.Profunctor.Rep ( -- * Representable Profunctors Rep(..), tabulated -- * Corepresentable Profunctors , Corep(..), cotabulated ) where import Control.Arrow import Control.Comonad import Data.Functor.Compose import Data.Functor.Identity import Data.Profunctor import Data.Profunctor.Composition import Data.Proxy import Data.Tagged -- * Representable Profunctors -- | A 'Profunctor' @p@ is representable if there exists a 'Functor' @f@ such that -- @p d c@ is isomorphic to @d -> f c@. class (Functor f, Profunctor p) => Rep f p where tabulate :: (d -> f c) -> p d c rep :: p d c -> d -> f c instance Rep Identity (->) where tabulate f = runIdentity . f rep f = Identity . f instance (Monad m, Functor m) => Rep m (Kleisli m) where tabulate = Kleisli rep = runKleisli instance Functor f => Rep f (UpStar f) where tabulate = UpStar rep = runUpStar -- | The composition of two representable profunctors is representable by the composition of their representations. instance (Rep f p, Rep g q) => Rep (Compose f g) (Procompose p q) where tabulate f = Procompose (tabulate (getCompose . f)) (tabulate id) rep (Procompose f g) d = Compose $ rep g <$> rep f d -- | 'tabulate' and 'rep' form two halves of an isomorphism. -- -- This can be used with the combinators from the @lens@ package. -- -- @'tabulated' :: 'Rep' f p => 'Iso'' (d -> f c) (p d c)@ tabulated :: (Profunctor r, Functor h, Rep f p, Rep g q) => r (p d c) (h (q d' c')) -> r (d -> f c) (h (d' -> g c')) tabulated = dimap tabulate (fmap rep) -- * Corepresentable Profunctors -- | A 'Profunctor' @p@ is representable if there exists a 'Functor' @f@ such that -- @p d c@ is isomorphic to @d -> f c@. class (Functor f, Profunctor p) => Corep f p where cotabulate :: (f d -> c) -> p d c corep :: p d c -> f d -> c instance Corep Identity (->) where cotabulate f = f . Identity corep f (Identity d) = f d instance Functor w => Corep w (Cokleisli w) where cotabulate = Cokleisli corep = runCokleisli instance Corep Proxy Tagged where cotabulate f = Tagged (f Proxy) corep (Tagged a) _ = a instance Functor f => Corep f (DownStar f) where cotabulate = DownStar corep = runDownStar instance (Corep f p, Corep g q) => Corep (Compose g f) (Procompose p q) where cotabulate f = Procompose (cotabulate id) (cotabulate (f . Compose)) corep (Procompose f g) (Compose d) = corep g $ corep f <$> d -- | 'cotabulate' and 'corep' form two halves of an isomorphism. -- -- This can be used with the combinators from the @lens@ package. -- -- @'tabulated' :: 'Corep' f p => 'Iso'' (f d -> c) (p d c)@ cotabulated :: (Profunctor r, Functor h, Corep f p, Corep g q) => r (p d c) (h (q d' c')) -> r (f d -> c) (h (g d' -> c')) cotabulated = dimap cotabulate (fmap corep)