{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE Safe #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Data.Profunctor.Rep
-- Copyright   :  (C) 2011-2015 Edward Kmett,
-- License     :  BSD-style (see the file LICENSE)
--
-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
-- Stability   :  provisional
-- Portability :  Type-Families
--
----------------------------------------------------------------------------
module Data.Profunctor.Rep
  (
  -- * Representable Profunctors
    Representable(..)
  , tabulated
  , firstRep, secondRep
  -- * Corepresentable Profunctors
  , Corepresentable(..)
  , cotabulated
  , unfirstCorep, unsecondCorep
  , closedCorep
  -- * Prep -| Star
  , Prep(..)
  , prepAdj
  , unprepAdj
  , prepUnit
  , prepCounit
  -- * Coprep -| Costar
  , Coprep(..)
  , coprepAdj
  , uncoprepAdj
  , coprepUnit
  , coprepCounit
  ) where

import Control.Applicative
import Control.Arrow
import Control.Comonad
import Control.Monad ((>=>))
import Data.Functor.Identity
import Data.Profunctor
import Data.Profunctor.Sieve
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 (Sieve p (Rep p), Strong p) => Representable p where
  type Rep p :: * -> *
  -- | Laws:
  --
  -- @
  -- 'tabulate' '.' 'sieve' ≡ 'id'
  -- 'sieve' '.' 'tabulate' ≡ 'id'
  -- @
  tabulate :: (d -> Rep p c) -> p d c

-- | Default definition for 'first'' given that p is 'Representable'.
firstRep :: Representable p => p a b -> p (a, c) (b, c)
firstRep :: forall (p :: * -> * -> *) a b c.
Representable p =>
p a b -> p (a, c) (b, c)
firstRep p a b
p = forall (p :: * -> * -> *) d c.
Representable p =>
(d -> Rep p c) -> p d c
tabulate forall a b. (a -> b) -> a -> b
$ \(a
a,c
c) -> (\b
b -> (b
b, c
c)) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (p :: * -> * -> *) (f :: * -> *) a b.
Sieve p f =>
p a b -> a -> f b
sieve p a b
p a
a

-- | Default definition for 'second'' given that p is 'Representable'.
secondRep :: Representable p => p a b -> p (c, a) (c, b)
secondRep :: forall (p :: * -> * -> *) a b c.
Representable p =>
p a b -> p (c, a) (c, b)
secondRep p a b
p = forall (p :: * -> * -> *) d c.
Representable p =>
(d -> Rep p c) -> p d c
tabulate forall a b. (a -> b) -> a -> b
$ \(c
c,a
a) -> (,) c
c forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (p :: * -> * -> *) (f :: * -> *) a b.
Sieve p f =>
p a b -> a -> f b
sieve p a b
p a
a

instance Representable (->) where
  type Rep (->) = Identity
  tabulate :: forall d c. (d -> Rep (->) c) -> d -> c
tabulate d -> Rep (->) c
f = forall a. Identity a -> a
runIdentity forall b c a. (b -> c) -> (a -> b) -> a -> c
. d -> Rep (->) c
f
  {-# INLINE tabulate #-}

instance (Monad m, Functor m) => Representable (Kleisli m) where
  type Rep (Kleisli m) = m
  tabulate :: forall d c. (d -> Rep (Kleisli m) c) -> Kleisli m d c
tabulate = forall (m :: * -> *) a b. (a -> m b) -> Kleisli m a b
Kleisli
  {-# INLINE tabulate #-}

instance Functor f => Representable (Star f) where
  type Rep (Star f) = f
  tabulate :: forall d c. (d -> Rep (Star f) c) -> Star f d c
tabulate = forall {k} (f :: k -> *) d (c :: k). (d -> f c) -> Star f d c
Star
  {-# INLINE tabulate #-}

instance Representable (Forget r) where
  type Rep (Forget r) = Const r
  tabulate :: forall d c. (d -> Rep (Forget r) c) -> Forget r d c
tabulate = forall {k} r a (b :: k). (a -> r) -> Forget r a b
Forget forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall {k} a (b :: k). Const a b -> a
getConst forall b c a. (b -> c) -> (a -> b) -> a -> c
.)
  {-# INLINE tabulate #-}

{- TODO: coproducts and products
instance (Representable p, Representable q) => Representable (Bifunctor.Product p q)
  type Rep (Bifunctor.Product p q) = Functor.Product p q

instance (Corepresentable p, Corepresentable q) => Corepresentable (Bifunctor.Product p q) where
  type Rep (Bifunctor.Product p q) = Functor.Sum p q
-}

type Iso s t a b = forall p f. (Profunctor p, Functor f) => p a (f b) -> p s (f t)

-- | 'tabulate' and 'sieve' form two halves of an isomorphism.
--
-- This can be used with the combinators from the @lens@ package.
--
-- @'tabulated' :: 'Representable' p => 'Iso'' (d -> 'Rep' p c) (p d c)@
tabulated :: (Representable p, Representable q) => Iso (d -> Rep p c) (d' -> Rep q c') (p d c) (q d' c')
tabulated :: forall (p :: * -> * -> *) (q :: * -> * -> *) d c d' c'.
(Representable p, Representable q) =>
Iso (d -> Rep p c) (d' -> Rep q c') (p d c) (q d' c')
tabulated = forall (p :: * -> * -> *) a b c d.
Profunctor p =>
(a -> b) -> (c -> d) -> p b c -> p a d
dimap forall (p :: * -> * -> *) d c.
Representable p =>
(d -> Rep p c) -> p d c
tabulate (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall (p :: * -> * -> *) (f :: * -> *) a b.
Sieve p f =>
p a b -> a -> f b
sieve)
{-# INLINE tabulated #-}

-- * Corepresentable Profunctors

-- | A 'Profunctor' @p@ is 'Corepresentable' if there exists a 'Functor' @f@ such that
-- @p d c@ is isomorphic to @f d -> c@.
class (Cosieve p (Corep p), Costrong p) => Corepresentable p where
  type Corep p :: * -> *
  -- | Laws:
  --
  -- @
  -- 'cotabulate' '.' 'cosieve' ≡ 'id'
  -- 'cosieve' '.' 'cotabulate' ≡ 'id'
  -- @
  cotabulate :: (Corep p d -> c) -> p d c

-- | Default definition for 'unfirst' given that @p@ is 'Corepresentable'.
unfirstCorep :: Corepresentable p => p (a, d) (b, d) -> p a b
unfirstCorep :: forall (p :: * -> * -> *) a d b.
Corepresentable p =>
p (a, d) (b, d) -> p a b
unfirstCorep p (a, d) (b, d)
p = forall (p :: * -> * -> *) d c.
Corepresentable p =>
(Corep p d -> c) -> p d c
cotabulate Corep p a -> b
f
  where f :: Corep p a -> b
f Corep p a
fa = b
b where (b
b, d
d) = forall (p :: * -> * -> *) (f :: * -> *) a b.
Cosieve p f =>
p a b -> f a -> b
cosieve p (a, d) (b, d)
p ((\a
a -> (a
a, d
d)) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Corep p a
fa)

-- | Default definition for 'unsecond' given that @p@ is 'Corepresentable'.
unsecondCorep :: Corepresentable p => p (d, a) (d, b) -> p a b
unsecondCorep :: forall (p :: * -> * -> *) d a b.
Corepresentable p =>
p (d, a) (d, b) -> p a b
unsecondCorep p (d, a) (d, b)
p = forall (p :: * -> * -> *) d c.
Corepresentable p =>
(Corep p d -> c) -> p d c
cotabulate Corep p a -> b
f
  where f :: Corep p a -> b
f Corep p a
fa = b
b where (d
d, b
b) = forall (p :: * -> * -> *) (f :: * -> *) a b.
Cosieve p f =>
p a b -> f a -> b
cosieve p (d, a) (d, b)
p ((,) d
d forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Corep p a
fa)

-- | Default definition for 'closed' given that @p@ is 'Corepresentable'
closedCorep :: Corepresentable p => p a b -> p (x -> a) (x -> b)
closedCorep :: forall (p :: * -> * -> *) a b x.
Corepresentable p =>
p a b -> p (x -> a) (x -> b)
closedCorep p a b
p = forall (p :: * -> * -> *) d c.
Corepresentable p =>
(Corep p d -> c) -> p d c
cotabulate forall a b. (a -> b) -> a -> b
$ \Corep p (x -> a)
fs x
x -> forall (p :: * -> * -> *) (f :: * -> *) a b.
Cosieve p f =>
p a b -> f a -> b
cosieve p a b
p (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a b. (a -> b) -> a -> b
$ x
x) Corep p (x -> a)
fs)

instance Corepresentable (->) where
  type Corep (->) = Identity
  cotabulate :: forall d c. (Corep (->) d -> c) -> d -> c
cotabulate Corep (->) d -> c
f = Corep (->) d -> c
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Identity a
Identity
  {-# INLINE cotabulate #-}

instance Functor w => Corepresentable (Cokleisli w) where
  type Corep (Cokleisli w) = w
  cotabulate :: forall d c. (Corep (Cokleisli w) d -> c) -> Cokleisli w d c
cotabulate = forall {k} (w :: k -> *) (a :: k) b. (w a -> b) -> Cokleisli w a b
Cokleisli
  {-# INLINE cotabulate #-}

instance Corepresentable Tagged where
  type Corep Tagged = Proxy
  cotabulate :: forall d c. (Corep Tagged d -> c) -> Tagged d c
cotabulate Corep Tagged d -> c
f = forall {k} (s :: k) b. b -> Tagged s b
Tagged (Corep Tagged d -> c
f forall {k} (t :: k). Proxy t
Proxy)
  {-# INLINE cotabulate #-}

instance Functor f => Corepresentable (Costar f) where
  type Corep (Costar f) = f
  cotabulate :: forall d c. (Corep (Costar f) d -> c) -> Costar f d c
cotabulate = forall {k} (f :: k -> *) (d :: k) c. (f d -> c) -> Costar f d c
Costar
  {-# INLINE cotabulate #-}

-- | 'cotabulate' and 'cosieve' form two halves of an isomorphism.
--
-- This can be used with the combinators from the @lens@ package.
--
-- @'cotabulated' :: 'Corep' f p => 'Iso'' (f d -> c) (p d c)@
cotabulated :: (Corepresentable p, Corepresentable q) => Iso (Corep p d -> c) (Corep q d' -> c') (p d c) (q d' c')
cotabulated :: forall (p :: * -> * -> *) (q :: * -> * -> *) d c d' c'.
(Corepresentable p, Corepresentable q) =>
Iso (Corep p d -> c) (Corep q d' -> c') (p d c) (q d' c')
cotabulated = forall (p :: * -> * -> *) a b c d.
Profunctor p =>
(a -> b) -> (c -> d) -> p b c -> p a d
dimap forall (p :: * -> * -> *) d c.
Corepresentable p =>
(Corep p d -> c) -> p d c
cotabulate (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall (p :: * -> * -> *) (f :: * -> *) a b.
Cosieve p f =>
p a b -> f a -> b
cosieve)
{-# INLINE cotabulated #-}

--------------------------------------------------------------------------------
-- * Prep
--------------------------------------------------------------------------------

-- | @'Prep' -| 'Star' :: [Hask, Hask] -> Prof@
--
-- This gives rise to a monad in @Prof@, @('Star'.'Prep')@, and
-- a comonad in @[Hask,Hask]@ @('Prep'.'Star')@
--
-- 'Prep' has a polymorphic kind since @5.6@.

-- Prep :: (Type -> k -> Type) -> (k -> Type)
data Prep p a where
  Prep :: x -> p x a -> Prep p a

instance Profunctor p => Functor (Prep p) where
  fmap :: forall a b. (a -> b) -> Prep p a -> Prep p b
fmap a -> b
f (Prep x
x p x a
p) = forall {k} x (p :: * -> k -> *) (a :: k). x -> p x a -> Prep p a
Prep x
x (forall (p :: * -> * -> *) b c a.
Profunctor p =>
(b -> c) -> p a b -> p a c
rmap a -> b
f p x a
p)

instance (Applicative (Rep p), Representable p) => Applicative (Prep p) where
  pure :: forall a. a -> Prep p a
pure a
a = forall {k} x (p :: * -> k -> *) (a :: k). x -> p x a -> Prep p a
Prep () forall a b. (a -> b) -> a -> b
$ forall (p :: * -> * -> *) d c.
Representable p =>
(d -> Rep p c) -> p d c
tabulate forall a b. (a -> b) -> a -> b
$ forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. Applicative f => a -> f a
pure a
a
  Prep x
xf p x (a -> b)
pf <*> :: forall a b. Prep p (a -> b) -> Prep p a -> Prep p b
<*> Prep x
xa p x a
pa = forall {k} x (p :: * -> k -> *) (a :: k). x -> p x a -> Prep p a
Prep (x
xf,x
xa) (forall (p :: * -> * -> *) d c.
Representable p =>
(d -> Rep p c) -> p d c
tabulate (x, x) -> Rep p b
go) where
    go :: (x, x) -> Rep p b
go (x
xf',x
xa') = forall (p :: * -> * -> *) (f :: * -> *) a b.
Sieve p f =>
p a b -> a -> f b
sieve p x (a -> b)
pf x
xf' forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (p :: * -> * -> *) (f :: * -> *) a b.
Sieve p f =>
p a b -> a -> f b
sieve p x a
pa x
xa'

instance (Monad (Rep p), Representable p) => Monad (Prep p) where
  return :: forall a. a -> Prep p a
return a
a = forall {k} x (p :: * -> k -> *) (a :: k). x -> p x a -> Prep p a
Prep () forall a b. (a -> b) -> a -> b
$ forall (p :: * -> * -> *) d c.
Representable p =>
(d -> Rep p c) -> p d c
tabulate forall a b. (a -> b) -> a -> b
$ forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Monad m => a -> m a
return a
a
  Prep x
xa p x a
pa >>= :: forall a b. Prep p a -> (a -> Prep p b) -> Prep p b
>>= a -> Prep p b
f = forall {k} x (p :: * -> k -> *) (a :: k). x -> p x a -> Prep p a
Prep x
xa forall a b. (a -> b) -> a -> b
$ forall (p :: * -> * -> *) d c.
Representable p =>
(d -> Rep p c) -> p d c
tabulate forall a b. (a -> b) -> a -> b
$ forall (p :: * -> * -> *) (f :: * -> *) a b.
Sieve p f =>
p a b -> a -> f b
sieve p x a
pa forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> \a
a -> case a -> Prep p b
f a
a of
    Prep x
xb p x b
pb -> forall (p :: * -> * -> *) (f :: * -> *) a b.
Sieve p f =>
p a b -> a -> f b
sieve p x b
pb x
xb

prepAdj :: (forall a. Prep p a -> g a) -> p :-> Star g
prepAdj :: forall {k} (p :: * -> k -> *) (g :: k -> *).
(forall (a :: k). Prep p a -> g a) -> p :-> Star g
prepAdj forall (a :: k). Prep p a -> g a
k p a b
p = forall {k} (f :: k -> *) d (c :: k). (d -> f c) -> Star f d c
Star forall a b. (a -> b) -> a -> b
$ \a
x -> forall (a :: k). Prep p a -> g a
k (forall {k} x (p :: * -> k -> *) (a :: k). x -> p x a -> Prep p a
Prep a
x p a b
p)

unprepAdj :: (p :-> Star g) -> Prep p a -> g a
unprepAdj :: forall {k} (p :: * -> k -> *) (g :: k -> *) (a :: k).
(p :-> Star g) -> Prep p a -> g a
unprepAdj p :-> Star g
k (Prep x
x p x a
p) = forall {k} (f :: k -> *) d (c :: k). Star f d c -> d -> f c
runStar (p :-> Star g
k p x a
p) x
x

prepUnit :: p :-> Star (Prep p)
prepUnit :: forall {k} (p :: * -> k -> *). p :-> Star (Prep p)
prepUnit p a b
p = forall {k} (f :: k -> *) d (c :: k). (d -> f c) -> Star f d c
Star forall a b. (a -> b) -> a -> b
$ \a
x -> forall {k} x (p :: * -> k -> *) (a :: k). x -> p x a -> Prep p a
Prep a
x p a b
p

prepCounit :: Prep (Star f) a -> f a
prepCounit :: forall {k} (f :: k -> *) (a :: k). Prep (Star f) a -> f a
prepCounit (Prep x
x Star f x a
p) = forall {k} (f :: k -> *) d (c :: k). Star f d c -> d -> f c
runStar Star f x a
p x
x

--------------------------------------------------------------------------------
-- * Coprep
--------------------------------------------------------------------------------

-- | 'Prep' has a polymorphic kind since @5.6@.

-- Coprep :: (k -> Type -> Type) -> (k -> Type)
newtype Coprep p a = Coprep { forall {k} (p :: k -> * -> *) (a :: k).
Coprep p a -> forall r. p a r -> r
runCoprep :: forall r. p a r -> r }

instance Profunctor p => Functor (Coprep p) where
  fmap :: forall a b. (a -> b) -> Coprep p a -> Coprep p b
fmap a -> b
f (Coprep forall r. p a r -> r
g) = forall {k} (p :: k -> * -> *) (a :: k).
(forall r. p a r -> r) -> Coprep p a
Coprep (forall r. p a r -> r
g forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (p :: * -> * -> *) a b c.
Profunctor p =>
(a -> b) -> p b c -> p a c
lmap a -> b
f)

-- | @'Coprep' -| 'Costar' :: [Hask, Hask]^op -> Prof@
--
-- Like all adjunctions this gives rise to a monad and a comonad.
--
-- This gives rise to a monad on Prof @('Costar'.'Coprep')@ and
-- a comonad on @[Hask, Hask]^op@ given by @('Coprep'.'Costar')@ which
-- is a monad in @[Hask,Hask]@
coprepAdj :: (forall a. f a -> Coprep p a) -> p :-> Costar f
coprepAdj :: forall {k} (f :: k -> *) (p :: k -> * -> *).
(forall (a :: k). f a -> Coprep p a) -> p :-> Costar f
coprepAdj forall (a :: k). f a -> Coprep p a
k p a b
p = forall {k} (f :: k -> *) (d :: k) c. (f d -> c) -> Costar f d c
Costar forall a b. (a -> b) -> a -> b
$ \f a
f -> forall {k} (p :: k -> * -> *) (a :: k).
Coprep p a -> forall r. p a r -> r
runCoprep (forall (a :: k). f a -> Coprep p a
k f a
f) p a b
p

uncoprepAdj :: (p :-> Costar f) -> f a -> Coprep p a
uncoprepAdj :: forall {k} (p :: k -> * -> *) (f :: k -> *) (a :: k).
(p :-> Costar f) -> f a -> Coprep p a
uncoprepAdj p :-> Costar f
k f a
f = forall {k} (p :: k -> * -> *) (a :: k).
(forall r. p a r -> r) -> Coprep p a
Coprep forall a b. (a -> b) -> a -> b
$ \p a r
p -> forall {k} (f :: k -> *) (d :: k) c. Costar f d c -> f d -> c
runCostar (p :-> Costar f
k p a r
p) f a
f

coprepUnit :: p :-> Costar (Coprep p)
coprepUnit :: forall {k} (p :: k -> * -> *). p :-> Costar (Coprep p)
coprepUnit p a b
p = forall {k} (f :: k -> *) (d :: k) c. (f d -> c) -> Costar f d c
Costar forall a b. (a -> b) -> a -> b
$ \Coprep p a
f -> forall {k} (p :: k -> * -> *) (a :: k).
Coprep p a -> forall r. p a r -> r
runCoprep Coprep p a
f p a b
p

coprepCounit :: f a -> Coprep (Costar f) a
coprepCounit :: forall {k} (f :: k -> *) (a :: k). f a -> Coprep (Costar f) a
coprepCounit f a
f = forall {k} (p :: k -> * -> *) (a :: k).
(forall r. p a r -> r) -> Coprep p a
Coprep forall a b. (a -> b) -> a -> b
$ \Costar f a r
p -> forall {k} (f :: k -> *) (d :: k) c. Costar f d c -> f d -> c
runCostar Costar f a r
p f a
f