module Data.Profunctor.Optic.Property where import Control.Applicative import Data.Profunctor.Optic.Prelude import Data.Profunctor.Optic.Type import Data.Profunctor.Optic.Iso import Data.Profunctor.Optic.View import Data.Profunctor.Optic.Setter import Data.Profunctor.Optic.Lens import Data.Profunctor.Optic.Prism import Data.Profunctor.Optic.Grate import Data.Profunctor.Optic.Fold import Data.Profunctor.Optic.Fold0 import Data.Profunctor.Optic.Cofold import Data.Profunctor.Optic.Traversal import Data.Profunctor.Optic.Traversal0 import Data.Profunctor.Optic.Cotraversal --------------------------------------------------------------------- -- 'Iso' --------------------------------------------------------------------- iso_fromto' :: Eq s => Iso' s a -> s -> Bool iso_fromto' o = withIso o iso_fromto iso_tofrom' :: Eq a => Iso' s a -> a -> Bool iso_tofrom' o = withIso o iso_tofrom iso_fromto :: Eq s => (s -> a) -> (a -> s) -> s -> Bool iso_fromto sa as s = as (sa s) == s iso_tofrom :: Eq a => (s -> a) -> (a -> s) -> a -> Bool iso_tofrom sa as a = sa (as a) == a --------------------------------------------------------------------- -- 'Prism' --------------------------------------------------------------------- -- If we are able to view an existing focus, then building it will return the original structure. prism_tofrom :: Eq s => (s -> s + a) -> (a -> s) -> s -> Bool prism_tofrom seta bt s = either id bt (seta s) == s -- If we build a whole from any focus, that whole must contain a focus. prism_fromto :: Eq s => Eq a => (s -> s + a) -> (a -> s) -> a -> Bool prism_fromto seta bt a = seta (bt a) == Right a prism_tofrom' :: Eq s => Prism' s a -> s -> Bool prism_tofrom' o = withPrism o prism_tofrom -- Reviewing a value with a 'Prism' and then previewing returns the value. prism_fromto' :: Eq s => Eq a => Prism' s a -> a -> Bool prism_fromto' o = withPrism o prism_fromto --------------------------------------------------------------------- -- 'Lens' --------------------------------------------------------------------- -- | A 'Lens' is a valid 'Traversal' with the following additional laws: -- -- * @view o (set o b a) ≡ b@ -- -- * @set o (view o a) a ≡ a@ -- -- * @set o c (set o b a) ≡ set o c a@ -- lens_tofrom :: Eq s => (s -> a) -> (s -> a -> s) -> s -> Bool lens_tofrom sa sas s = sas s (sa s) == s lens_fromto :: Eq a => (s -> a) -> (s -> a -> s) -> s -> a -> Bool lens_fromto sa sas s a = sa (sas s a) == a lens_idempotent :: Eq s => (s -> a -> s) -> s -> a -> a -> Bool lens_idempotent sas s a1 a2 = sas (sas s a1) a2 == sas s a2 -- | Putting back what you got doesn't change anything. lens_tofrom' :: Eq s => Lens' s a -> s -> Bool lens_tofrom' o = withLens o lens_tofrom -- | You get back what you put in. lens_fromto' :: Eq a => Lens' s a -> s -> a -> Bool lens_fromto' o = withLens o lens_fromto -- | Setting twice is the same as setting once. lens_idempotent' :: Eq s => Lens' s a -> s -> a -> a -> Bool lens_idempotent' o = withLens o $ const lens_idempotent --------------------------------------------------------------------- -- 'Grate' --------------------------------------------------------------------- -- | The 'Grate' laws are that of an algebra for a parameterised continuation monad. -- -- * @grate ($ s) ≡ s@ -- -- * @grate (\k -> h (k . sabt)) ≡ sabt (\k -> h ($ k))@ -- grate_pure :: Eq s => (((s -> a) -> a) -> s) -> s -> Bool grate_pure sabt s = sabt ($ s) == s grate_pure' :: Eq s => (((s -> a) -> a) -> s) -> s -> a -> Bool grate_pure' sabt s a = sabt (const a) == s --------------------------------------------------------------------- -- 'Traversal0' --------------------------------------------------------------------- atraversal_tofrom :: Eq a => Eq s => (s -> s + a) -> (s -> a -> s) -> s -> a -> Bool atraversal_tofrom seta sbt s a = seta (sbt s a) == either (Left . flip const a) Right (seta s) atraversal_fromto :: Eq s => (s -> s + a) -> (s -> a -> s) -> s -> Bool atraversal_fromto seta sbt s = either id (sbt s) (seta s) == s atraversal_idempotent :: Eq s => (s -> a -> s) -> s -> a -> a -> Bool atraversal_idempotent sbt s a1 a2 = sbt (sbt s a1) a2 == sbt s a2 atraversal_tofrom' :: Eq a => Eq s => Traversal0' s a -> s -> a -> Bool atraversal_tofrom' o = withTraversal0 o atraversal_tofrom atraversal_fromto' :: Eq s => Traversal0' s a -> s -> Bool atraversal_fromto' o = withTraversal0 o atraversal_fromto atraversal_idempotent' :: Eq s => Traversal0' s a -> s -> a -> a -> Bool atraversal_idempotent' o = withTraversal0 o $ const atraversal_idempotent --------------------------------------------------------------------- -- 'Traversal' --------------------------------------------------------------------- -- | 'Traversal' is a valid 'Setter' with the following additional laws: -- -- * @t pure ≡ pure@ -- -- * @fmap (t f) . t g ≡ getCompose . t (Compose . fmap f . g)@ -- -- These can be restated in terms of 'traverseOf': -- -- * @traverseOf t (Identity . f) ≡ Identity (fmap f)@ -- -- * @Compose . fmap (traverseOf t f) . traverseOf t g == traverseOf t (Compose . fmap f . g)@ -- -- See also < https://www.cs.ox.ac.uk/jeremy.gibbons/publications/iterator.pdf > -- traverse_pure :: forall f s a. (Applicative f, Eq (f s)) => ((a -> f a) -> s -> f s) -> s -> Bool traverse_pure o s = o pure s == (pure s :: f s) --traverse_compose :: (Applicative f, Applicative g, Eq (f (g s))) => Traversal' s a -> (a -> g a) -> (a -> f a) -> s -> Bool --traverse_compose t f g s = (fmap (t f) . t g) s == (getCompose . t (Compose . fmap f . g)) s --------------------------------------------------------------------- -- 'Setter' --------------------------------------------------------------------- -- | A 'Setter' is only legal if the following 3 laws hold: -- -- 1. @set o y (set o x a) ≡ set o y a@ -- -- 2. @over o id ≡ id@ -- -- 3. @over o f . over o g ≡ over o (f . g)@ setter_id :: Eq s => Setter' s a -> s -> Bool setter_id o s = over o id s == s setter_compose :: Eq s => Setter' s a -> (a -> a) -> (a -> a) -> s -> Bool setter_compose o f g s = (over o f . over o g) s == over o (f . g) s setter_idempotent :: Eq s => Setter' s a -> s -> a -> a -> Bool setter_idempotent o s a b = set o b (set o a s) == set o b s