{-# LANGUAGE CPP #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE QuantifiedConstraints #-} #ifndef MIN_VERSION_profunctors #define MIN_VERSION_profunctors(x,y,z) 1 #endif module Data.Profunctor.Optic.Types ( -- * Optic, IndexedOptic, & CoindexedOptic Optic, Optic' , IndexedOptic, IndexedOptic' , CoindexedOptic, CoindexedOptic' -- * Iso & Equality , Iso, Iso', Equality, Equality' -- * Lens , Lens, Lens', Ixlens, Ixlens' -- * Prism , Prism, Prism', Cxprism, Cxprism' -- * Grate , Grate, Grate', Cxgrate, Cxgrate' -- * Affine & Option , Affine, Affine', Ixaffine, Ixaffine' , Option, Ixoption -- * Grism , Grism , Grism' -- * Traversal, Traversal1, Fold & Fold1 , Traversal , Traversal' , Ixtraversal , Ixtraversal' , Traversal1 , Traversal1' , Ixtraversal1, Ixtraversal1' , Fold, Ixfold , Fold1, Ixfold1 -- * Cotraversal , Cotraversal , Cotraversal' -- * View & Review , PrimView, View, Ixview, PrimReview, Review, Cxview -- * Setter & Resetter , Setter, Setter', Ixsetter, Ixsetter' , Resetter, Resetter', Cxsetter, Cxsetter' -- * Coapplicative , Coapplicative(..), Branch(..) , between -- * 'Re' , Re(..), re , module Export ) where import Data.Bifunctor (Bifunctor(..)) import Data.Functor.Apply (Apply(..)) import Data.Profunctor.Optic.Import hiding (branch) import Data.Profunctor.Extra as Export (type (+)) import Data.Profunctor.Types as Export import qualified Control.Arrow as A import Data.List.NonEmpty as L1 import qualified Data.Bifunctor as B -- $setup -- >>> :set -XCPP -- >>> :set -XNoOverloadedStrings -- >>> :load Data.Profunctor.Optic --------------------------------------------------------------------- -- Optic --------------------------------------------------------------------- type Optic p s t a b = p a b -> p s t type Optic' p s a = Optic p s s a a type IndexedOptic p i s t a b = p (i , a) b -> p (i , s) t type IndexedOptic' p i s a = IndexedOptic p i s s a a type CoindexedOptic p k s t a b = p a (k -> b) -> p s (k -> t) type CoindexedOptic' p k t b = CoindexedOptic p k t t b b --------------------------------------------------------------------- -- Iso & Equality --------------------------------------------------------------------- -- | 'Iso' -- -- \( \mathsf{Iso}\;S\;A = S \cong A \) -- type Iso s t a b = forall p. Profunctor p => Optic p s t a b type Iso' s a = Iso s s a a type Equality s t a b = forall p. Optic p s t a b type Equality' s a = Equality s s a a --------------------------------------------------------------------- -- Lens --------------------------------------------------------------------- -- | Lenses access one piece of a product. -- -- \( \mathsf{Lens}\;S\;A = \exists C, S \cong C \times A \) -- type Lens s t a b = forall p. Strong p => Optic p s t a b type Lens' s a = Lens s s a a type Ixlens i s t a b = forall p. Strong p => IndexedOptic p i s t a b type Ixlens' i s a = Ixlens i s s a a --------------------------------------------------------------------- -- Prism --------------------------------------------------------------------- -- | Prisms access one piece of a sum. -- -- \( \mathsf{Prism}\;S\;A = \exists D, S \cong D + A \) -- type Prism s t a b = forall p. Choice p => Optic p s t a b type Prism' s a = Prism s s a a type Cxprism k s t a b = forall p. Choice p => CoindexedOptic p k s t a b type Cxprism' k s a = Cxprism k s s a a --------------------------------------------------------------------- -- Grate --------------------------------------------------------------------- -- | Grates access the codomain of a function. -- -- \( \mathsf{Grate}\;S\;A = \exists I, S \cong I \to A \) -- type Grate s t a b = forall p. Closed p => Optic p s t a b type Grate' s a = Grate s s a a type Cxgrate k s t a b = forall p. Closed p => CoindexedOptic p k s t a b type Cxgrate' k s a = Cxgrate k s s a a type Colens s t a b = forall p. Costrong p => Optic p s t a b type Colens' s a = Colens s s a a type Cxlens k s t a b = forall p. Costrong p => CoindexedOptic p k s t a b type Cxlens' k s a = Cxlens k s s a a type Cotraversal0 s t a b = forall p. (Choice p, Closed p) => Optic p s t a b type Cotraversal0' t b = Cotraversal0 t t b b --------------------------------------------------------------------- -- Affine & Option --------------------------------------------------------------------- -- | A 'Affine' processes 0 or more parts of the whole, with no interactions. -- -- \( \mathsf{Affine}\;S\;A = \exists C, D, S \cong D + C \times A \) -- type Affine s t a b = forall p. (Choice p, Strong p) => Optic p s t a b type Affine' s a = Affine s s a a type Ixaffine i s t a b = forall p. (Choice p, Strong p) => IndexedOptic p i s t a b type Ixaffine' i s a = Ixaffine i s s a a -- | A 'Option' combines at most one element, with no interactions. -- type Option s a = forall p. (Choice p, Strong p, forall x. Contravariant (p x)) => Optic' p s a type Ixoption i s a = forall p. (Choice p, Strong p, forall x. Contravariant (p x)) => IndexedOptic' p i s a --------------------------------------------------------------------- -- Grism --------------------------------------------------------------------- -- | https://en.wikipedia.org/wiki/Grism -- type Grism s t a b = forall p. (Choice p, Closed p) => Optic p s t a b type Grism' t b = Grism t t b b --------------------------------------------------------------------- -- Traversal, Traversal1, Fold, & Fold1 --------------------------------------------------------------------- -- | A 'Traversal' processes 0 or more parts of the whole, with 'Applicative' interactions. -- -- \( \mathsf{Traversal}\;S\;A = \exists F : \mathsf{Traversable}, S \equiv F\,A \) -- type Traversal s t a b = forall p. (Choice p, Strong p, Representable p, Applicative (Rep p)) => Optic p s t a b type Traversal' s a = Traversal s s a a type Ixtraversal i s t a b = forall p. (Choice p, Strong p, Representable p, Applicative (Rep p)) => IndexedOptic p i s t a b type Ixtraversal' i s a = Ixtraversal i s s a a -- | A 'Traversal1' processes 1 or more parts of the whole, with 'Apply' interactions. -- -- \( \mathsf{Traversal1}\;S\;A = \exists F : \mathsf{Traversable1}, S \equiv F\,A \) -- type Traversal1 s t a b = forall p. (Strong p, Representable p, Apply (Rep p)) => Optic p s t a b type Traversal1' s a = Traversal1 s s a a type Ixtraversal1 i s t a b = forall p. (Strong p, Representable p, Apply (Rep p)) => IndexedOptic p i s t a b type Ixtraversal1' i s a = Ixtraversal1 i s s a a type Cofold0 t b = forall p. (Choice p, Closed p, Strong p, forall x. Contravariant (p x)) => Optic' p t b -- | A 'Fold1' combines 1 or more elements, with 'Semigroup' interactions. -- type Fold1 s a = forall p. (Strong p, Representable p, Apply (Rep p), forall x. Contravariant (p x)) => Optic' p s a type Ixfold1 i s a = forall p. (Strong p, Representable p, Apply (Rep p), forall x. Contravariant (p x)) => IndexedOptic' p i s a -- | A 'Fold' combines 0 or more elements, with 'Monoid' interactions. -- type Fold s a = forall p. (Choice p, Representable p, Applicative (Rep p), forall x. Contravariant (p x)) => Optic' p s a type Ixfold i s a = forall p. (Choice p, Representable p, Applicative (Rep p), forall x. Contravariant (p x)) => IndexedOptic' p i s a -- type Cofold t b = forall p. (Closed p, Corepresentable p, Coapplicative (Corep p), Bifunctor p) => Optic' p t b --------------------------------------------------------------------- -- Cotraversal --------------------------------------------------------------------- type Cotraversal s t a b = forall p. (Choice p, Closed p, Coapplicative (Corep p), Corepresentable p) => Optic p s t a b type Cotraversal' t b = Cotraversal t t b b --------------------------------------------------------------------- -- View & Review --------------------------------------------------------------------- type PrimView s t a b = forall p. (Profunctor p, forall x. Contravariant (p x)) => Optic p s t a b type View s a = forall p. (Strong p, forall x. Contravariant (p x)) => Optic' p s a type Ixview i s a = forall p. (Strong p, forall x. Contravariant (p x)) => IndexedOptic' p i s a type PrimReview s t a b = forall p. (Profunctor p, Bifunctor p) => Optic p s t a b type Review t b = forall p. (Closed p, Bifunctor p) => Optic' p t b type Cxview k t b = forall p. (Closed p, Bifunctor p) => CoindexedOptic' p k t b --------------------------------------------------------------------- -- Setter & Resetter --------------------------------------------------------------------- -- | A 'Setter' modifies part of a structure. -- -- \( \mathsf{Setter}\;S\;A = \exists F : \mathsf{Functor}, S \equiv F\,A \) -- type Setter s t a b = forall p. (Choice p, Strong p, Representable p, Applicative (Rep p), Distributive (Rep p)) => Optic p s t a b type Setter' s a = Setter s s a a type Ixsetter i s t a b = forall p. (Choice p, Strong p, Representable p, Applicative (Rep p), Distributive (Rep p)) => IndexedOptic p i s t a b type Ixsetter' i s a = Ixsetter i s s a a type Resetter s t a b = forall p. (Choice p, Closed p, Corepresentable p, Coapplicative (Corep p), Traversable (Corep p)) => Optic p s t a b type Resetter' s a = Resetter s s a a type Cxsetter k s t a b = forall p. (Choice p, Closed p, Corepresentable p, Coapplicative (Corep p), Traversable (Corep p)) => CoindexedOptic p k s t a b type Cxsetter' k t b = Cxsetter k t t b b --------------------------------------------------------------------- -- Branch & Coapplicative --------------------------------------------------------------------- -- branch . fmap Left == Left -- branch . fmap Right == Right -- (fmap Left ||| fmap Right) . branch == id -- >>> (fmap Left ||| fmap Right) . branch $ (Left 1) :| [Right 2] -- Left 1 :| [] -- class Functor f => Branch f where branch :: f (Either a b) -> Either (f a) (f b) cobranch :: Apply f => (f a, f b) -> f (a, b) cobranch = uncurry $ liftF2 (,) instance Branch Identity where branch (Identity ab) = either (Left . Identity) (Right . Identity) ab {- instance Branch (Const r) where branch (Const r) = Right (Const r) -} instance Branch (Tagged k) where branch (Tagged ab) = either (Left . Tagged) (Right . Tagged) ab instance Branch ((,) r) where branch (r, a) = either (Left . (r,)) (Right . (r,)) a instance Monoid m => Branch ((->) m) where branch f = either (Left . const) (Right . const) $ f mempty instance Branch NonEmpty where branch (Left x :| zs) = Left $ x :| foldr (either (:) (const id)) [] zs branch (Right y :| zs) = Right $ y :| foldr (either (const id) (:)) [] zs instance (Branch f, Branch g) => Branch (Compose f g) where branch (Compose ab) = B.bimap Compose Compose . branch . fmap branch $ ab class Branch f => Coapplicative f where -- either (f . copure) (g . copure) . branch == either f g . copure copure :: f a -> a instance Coapplicative Identity where copure (Identity a) = a instance Coapplicative (Tagged k) where copure (Tagged a) = a instance Coapplicative ((,) r) where copure (_, a) = a instance Monoid m => Coapplicative ((->) m) where copure f = f mempty instance Coapplicative NonEmpty where copure = L1.head catLefts :: [Either a b] -> [a] catLefts = foldr (either (:) (const id)) [] catRights :: [Either a b] -> [b] catRights = foldr (either (const id) (:)) [] instance (Coapplicative f, Coapplicative g) => Coapplicative (Compose f g) where copure (Compose a) = copure . fmap copure $ a #if MIN_VERSION_profunctors(5,4,0) instance Coapplicative f => Choice (Costar f) where left' (Costar f) = Costar $ either (Left . f) (Right . copure) . branch #endif -- | Can be used to rewrite -- -- > \g -> f . g . h -- -- to -- -- > between f h -- between :: (c -> d) -> (a -> b) -> (b -> c) -> a -> d between f g = (f .) . (. g) {-# INLINE between #-} --------------------------------------------------------------------- -- 'Re' --------------------------------------------------------------------- -- | Reverse an optic to obtain its dual. -- -- >>> 5 ^. re left' -- Left 5 -- -- >>> 6 ^. re (left' . from succ) -- Left 7 -- -- @ -- 're' . 're' ≡ id -- @ -- -- @ -- 're' :: 'Iso' s t a b -> 'Iso' b a t s -- 're' :: 'Lens' s t a b -> 'Colens' b a t s -- 're' :: 'Prism' s t a b -> 'Coprism' b a t s -- @ -- re :: Optic (Re p a b) s t a b -> Optic p b a t s re o = (between runRe Re) o id {-# INLINE re #-} -- | The 'Re' type and its instances witness the symmetry between the parameters of a 'Profunctor'. -- newtype Re p s t a b = Re { runRe :: p b a -> p t s } instance Profunctor p => Profunctor (Re p s t) where dimap f g (Re p) = Re (p . dimap g f) instance Strong p => Costrong (Re p s t) where unfirst (Re p) = Re (p . first') instance Costrong p => Strong (Re p s t) where first' (Re p) = Re (p . unfirst) instance Choice p => Cochoice (Re p s t) where unright (Re p) = Re (p . right') instance Cochoice p => Choice (Re p s t) where right' (Re p) = Re (p . unright) instance (Profunctor p, forall x. Contravariant (p x)) => Bifunctor (Re p s t) where first f (Re p) = Re (p . contramap f) second f (Re p) = Re (p . lmap f) instance Bifunctor p => Contravariant (Re p s t a) where contramap f (Re p) = Re (p . first f) --------------------------------------------------------------------- -- Orphan instances --------------------------------------------------------------------- instance Apply f => Apply (Star f a) where Star ff <.> Star fx = Star $ \a -> ff a <.> fx a instance Apply (Costar f a) where Costar ff <.> Costar fx = Costar $ \a -> ff a (fx a) #if !(MIN_VERSION_profunctors(5,4,0)) instance Contravariant f => Contravariant (Star f a) where contramap f (Star g) = Star $ contramap f . g #endif instance Contravariant f => Bifunctor (Costar f) where first f (Costar g) = Costar $ g . contramap f second f (Costar g) = Costar $ f . g {- #if !(MIN_VERSION_profunctors(5,5,0)) instance Cochoice (Forget r) where unleft (Forget f) = Forget $ f . Left unright (Forget f) = Forget $ f . Right #endif #if MIN_VERSION_profunctors(5,4,0) instance Comonad f => Choice (Costar f) where left' (Costar f) = Costar . runCostar . A.left . Costar $ f right' (Costar f) = Costar . runCostar . A.right . Costar $ f #endif -}