{-# LANGUAGE RankNTypes #-}

module Optics
  ( Optic
  , Adapter
  , Lens
  , Prism
  , Traversal
  , Monoidal(..)
  ) where

import Data.Profunctor
import Data.Distributive

class Profunctor p => Monoidal p where
  par :: p a b -> p c d -> p (a, c) (b, d)
  empty :: p () ()

cross :: (a -> c) -> (b -> d) -> (a, b) -> (c, d)
cross :: forall a c b d. (a -> c) -> (b -> d) -> (a, b) -> (c, d)
cross a -> c
f b -> d
g (a
x, b
y) = (a -> c
f a
x, b -> d
g b
y)

instance Monoidal (->) where
  par :: forall a c b d. (a -> c) -> (b -> d) -> (a, b) -> (c, d)
par = forall a c b d. (a -> c) -> (b -> d) -> (a, b) -> (c, d)
cross
  empty :: () -> ()
empty = forall a. a -> a
id

type Optic p a b s t = p a b -> p s t
type Adapter a b s t = forall p. (Profunctor p)     => Optic p a b s t
type Lens a b s t = forall p. (Strong p)            => Optic p a b s t
type Prism a b s t = forall p. (Costrong p)         => Optic p a b s t
type Traversal a b s t = forall p. ( Strong p
                                   , Costrong p
                                   , Monoidal p )   => Optic p a b s t