{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE Trustworthy #-}
-----------------------------------------------------------------------------
-- |
-- Copyright   :  (C) 2015 Edward Kmett
-- License     :  BSD-style (see the file LICENSE)
--
-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
-- Stability   :  provisional
-- Portability :  MPTCs, fundeps
--
----------------------------------------------------------------------------
module Data.Profunctor.Sieve
  ( Sieve(..)
  , Cosieve(..)
  ) where

import Control.Applicative
import Control.Arrow
import Control.Comonad
import Data.Functor.Identity
import Data.Profunctor
import Data.Proxy
import Data.Tagged

-- | A 'Profunctor' @p@ is a 'Sieve' __on__ @f@ if it is a subprofunctor of @'Star' f@.
--
-- That is to say it is a subset of @Hom(-,f=)@ closed under 'lmap' and 'rmap'.
--
-- Alternately, you can view it as a sieve __in__ the comma category @Hask/f@.
class (Profunctor p, Functor f) => Sieve p f | p -> f where
  sieve :: p a b -> a -> f b

instance Sieve (->) Identity where
  sieve :: forall a b. (a -> b) -> a -> Identity b
sieve a -> b
f = forall a. a -> Identity a
Identity forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> b
f
  {-# INLINE sieve #-}

instance (Monad m, Functor m) => Sieve (Kleisli m) m where
  sieve :: forall a b. Kleisli m a b -> a -> m b
sieve = forall (m :: * -> *) a b. Kleisli m a b -> a -> m b
runKleisli
  {-# INLINE sieve #-}

instance Functor f => Sieve (Star f) f where
  sieve :: forall a b. Star f a b -> a -> f b
sieve = forall {k} (f :: k -> *) d (c :: k). Star f d c -> d -> f c
runStar
  {-# INLINE sieve #-}

instance Sieve (Forget r) (Const r) where
  sieve :: forall a b. Forget r a b -> a -> Const r b
sieve = (forall {k} a (b :: k). a -> Const a b
Const forall b c a. (b -> c) -> (a -> b) -> a -> c
.) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {k} r a (b :: k). Forget r a b -> a -> r
runForget
  {-# INLINE sieve #-}

-- | A 'Profunctor' @p@ is a 'Cosieve' __on__ @f@ if it is a subprofunctor of @'Costar' f@.
--
-- That is to say it is a subset of @Hom(f-,=)@ closed under 'lmap' and 'rmap'.
--
-- Alternately, you can view it as a cosieve __in__ the comma category @f/Hask@.
class (Profunctor p, Functor f) => Cosieve p f | p -> f where
  cosieve :: p a b -> f a -> b

instance Cosieve (->) Identity where
  cosieve :: forall a b. (a -> b) -> Identity a -> b
cosieve a -> b
f (Identity a
d) = a -> b
f a
d
  {-# INLINE cosieve #-}

instance Functor w => Cosieve (Cokleisli w) w where
  cosieve :: forall a b. Cokleisli w a b -> w a -> b
cosieve = forall {k} (w :: k -> *) (a :: k) b. Cokleisli w a b -> w a -> b
runCokleisli
  {-# INLINE cosieve #-}

instance Cosieve Tagged Proxy where
  cosieve :: forall a b. Tagged a b -> Proxy a -> b
cosieve (Tagged b
a) Proxy a
_ = b
a
  {-# INLINE cosieve #-}

instance Functor f => Cosieve (Costar f) f where
  cosieve :: forall a b. Costar f a b -> f a -> b
cosieve = forall {k} (f :: k -> *) (d :: k) c. Costar f d c -> f d -> c
runCostar
  {-# INLINE cosieve #-}