{-# LANGUAGE Rank2Types #-} -- | This is the main module for end-users of lens-families. -- If you are not building your own optics such as lenses, traversals, grates, etc., but just using optics made by others, this is the only module you need. module Lens.Family2 ( -- * Lenses -- -- | This module provides 'LF.^.' for accessing fields and 'LF..~' and 'LF.%~' for setting and modifying fields. -- Lenses are composed with `Prelude..` from the @Prelude@ and `Prelude.id` is the identity lens. -- -- Lens composition in this library enjoys the following identities. -- -- * @x^.l1.l2 === x^.l1^.l2@ -- -- * @l1.l2 %~ f === l1 %~ l2 %~ f@ -- -- The identity lens behaves as follows. -- -- * @x^.id === x@ -- -- * @id %~ f === f@ -- -- The 'LF.&' operator, allows for a convenient way to sequence record updating: -- -- @record & l1 .~ value1 & l2 .~ value2@ -- -- Lenses are implemented in van Laarhoven style. -- Lenses have type @'Functor' f => (a -> f a) -> s -> f s@ and lens families have type @'Functor' f => (a i -> f (a j)) -> s i -> f (s j)@. -- -- Keep in mind that lenses and lens families can be used directly for functorial updates. -- For example, @_2 id@ gives you strength. -- -- > _2 id :: Functor f => (a, f b) -> f (a, b) -- -- Here is an example of code that uses the 'Maybe' functor to preserves sharing during update when possible. -- -- > -- | 'sharedUpdate' returns the *identical* object if the update doesn't change anything. -- > -- This is useful for preserving sharing. -- > sharedUpdate :: Eq a => LensLike' Maybe s a -> (a -> a) -> s -> s -- > sharedUpdate l f s = fromMaybe s (l f' s) -- > where -- > f' a | b == a = Nothing -- > | otherwise = Just b -- > where -- > b = f a -- * Traversals -- -- | 'LF.^.' can be used with traversals to access monoidal fields. -- The result will be a 'Data.Monid.mconcat' of all the fields referenced. -- The various @fooOf@ functions can be used to access different monoidal summaries of some kinds of values. -- -- '^?' can be used to access the first value of a traversal. -- 'Nothing' is returned when the traversal has no references. -- -- '^..' can be used with a traversals and will return a list of all fields referenced. -- -- When 'LF..~' is used with a traversal, all referenced fields will be set to the same value, and when 'LF.%~' is used with a traversal, all referenced fields will be modified with the same function. -- -- A variant of '^?' call 'matching' returns 'Either' a 'Right' value which is the first value of the traversal, or a 'Left' value which is a "proof" that the traversal has no elements. -- The "proof" consists of the original input structure, but in the case of polymorphic families, the type parameter is replaced with a fresh type variable, thus proving that the type parameter was unused. -- -- Like all optics, traversals can be composed with '.', and because every lens is automatically a traversal, lenses and traversals can be composed with '.' yielding a traversal. -- -- Traversals are implemented in van Laarhoven style. -- Traversals have type @'Applicative' f => (a -> f a) -> s -> f s@ and traversal families have type @'Applicative' f => (a i -> f (a j)) -> s i -> f (s j)@. -- -- * Grates -- -- | 'zipWithOf' can be used with grates to zip two structure together provided a binary operation. -- -- 'under' can be to modify each value in a structure according to a function. This works analogous to how 'over' works for lenses and traversals. -- -- 'LF.review' can be used with grates to construct a constant grate from a single value. This is like a 0-ary @zipWith@ function. -- -- 'degrating' can be used to build higher arity @zipWithOf@ functions: -- -- > zipWith3Of :: AGrate s t a b -> (a -> a -> a -> b) -> s -> s -> s -> t -- > zipWith3Of l f s1 s2 s3 = degrating l (\k -> f (k s1) (k s2) (k s3)) -- -- Like all optics, grates can be composed with '.', and 'id' is the identity grate. -- -- Grates are implemented in van Laarhoven style. -- -- Grates have type @'Functor' g => (g a -> a) -> g s -> s@ and grate families have type @'Functor' g => (g (a i) -> a j) -> g (s i) -> s j@. -- -- Keep in mind that grates and grate families can be used directly for functorial zipping. For example, -- -- > both sum :: Num a => [(a, a)] -> (a, a) -- -- will take a list of pairs return the sum of the first components and the sum of the second components. For another example, -- -- > cod id :: Functor f => f (r -> a) -> r -> f a -- -- will turn a functor full of functions into a function returning a functor full of results. -- * Adapters, Grids, and Prisms -- -- | The Adapter, Prism, and Grid optics are all 'AdapterLike' optics and typically not used directly, but either converted to a 'LensLike' optic using 'under', or into a 'GrateLike' optic using 'over'. -- See 'under' and 'over' for details about which conversions are possible. -- -- These optics are implemented in van Laarhoven style. -- -- * Adapters have type @('Functor' f, 'Functor' g) => (g a -> f a) -> g s -> f s@ and Adapters families have type @('Functor' f, 'Functor' g) => (g (a i) -> f (a j)) -> g (s i) -> f (s j)@. -- -- * Grids have type @('Applicative' f, 'Functor' g) => (g a -> f a) -> g s -> f s@ and Grids families have type @('Applicative' f, 'Functor' g) => (g (a i) -> f (a j)) -> g (s i) -> f (s j)@. -- -- * Prisms have type @('Applicative' f, 'Traversable' g) => (g a -> f a) -> g s -> f s@ and Prisms families have type @('Applicative' f, 'Traversable' g) => (g (a i) -> f (a j)) -> g (s i) -> f (s j)@. -- -- Keep in mind that these optics and their families can sometimes be used directly, without using 'over' and 'under'. Sometimes you can take advantage of the fact that -- -- @ -- LensLike f (g s) t (g a) b -- == -- AdapterLike f g s t a b -- == -- GrateLike g s (f t) a (f b) -- @ -- -- For example, if you have a grid for your structure to another type that has an @Arbitray@ instance, such as grid from a custom word type to 'Bool', e.g. @myWordBitVector :: (Applicative f, Functor g) => AdapterLike' f g MyWord Bool@, you can use the grid to create an @Arbitrary@ instance for your structure by directly applying 'LF.review': -- -- > instance Arbitrary MyWord where -- > arbitrary = review myWordBitVector arbitrary -- * Building and Finding Optics -- -- | To build your own optics, see "Lens.Family2.Unchecked". -- -- For stock optics, see "Lens.Family2.Stock". -- -- References: -- -- * <http://www.twanvl.nl/blog/haskell/cps-functional-references> -- -- * <http://r6.ca/blog/20120623T104901Z.html> -- -- * <http://comonad.com/reader/2012/mirrored-lenses/> -- -- * <http://conal.net/blog/posts/semantic-editor-combinators> -- -- * <https://r6research.livejournal.com/28050.html> -- * Documentation to, LF.view, (LF.^.) , folding, LF.views, (^..), (^?) , toListOf, allOf, anyOf, firstOf, lastOf, sumOf, productOf , lengthOf, nullOf , matching , over, (%~), set, (.~) , LF.review, zipWithOf, degrating , under, reset , (LF.&) -- * Pseudo-imperatives , (+~), (*~), (-~), (//~), (&&~), (||~), (<>~) -- * Types , Adapter, Adapter' , Prism, Prism' , Lens, Lens' , Traversal, Traversal' , Setter, Setter' , Getter, Getter' , Fold, Fold' , Grate, Grate' , Grid, Grid' , Reviewer, Reviewer' , LF.AdapterLike, LF.AdapterLike' , LF.LensLike, LF.LensLike' , LF.GrateLike, LF.GrateLike' , LF.FoldLike, LF.FoldLike' , LF.Constant , LF.Phantom , Identical ) where import qualified Lens.Family as LF import Lens.Family2.Unchecked type Grid s t a b = forall f g. (Applicative f, Functor g) => LF.AdapterLike f g s t a b type Grid' s a = forall f g. (Applicative f, Functor g) => LF.AdapterLike' f g s a type Fold s t a b = forall f. (LF.Phantom f, Applicative f) => LF.LensLike f s t a b type Fold' s a = forall f. (LF.Phantom f, Applicative f) => LF.LensLike' f s a type Getter s t a b = forall f. LF.Phantom f => LF.LensLike f s t a b type Getter' s a = forall f. LF.Phantom f=> LF.LensLike' f s a type Reviewer s t a b = forall f. LF.Phantom f => LF.GrateLike f s t a b type Reviewer' s a = forall f. LF.Phantom f => LF.GrateLike' f s a -- |'to' promotes a projection function to a read-only lens called a getter. -- To demote a lens to a projection function, use the section @(^.l)@ or @view l@. -- -- >>> (3 :+ 4, "example")^._1.to(abs) -- 5.0 :+ 0.0 to :: (s -> a) -> Getter s t a b to :: (s -> a) -> Getter s t a b to s -> a sa = (s -> a) -> LensLike f s t a b forall (f :: * -> *) s a t b. Phantom f => (s -> a) -> LensLike f s t a b LF.to s -> a sa -- | 'folding' promotes a \"toList\" function to a read-only traversal called a fold. -- -- To demote a traversal or fold to a \"toList\" function use the section @(^..l)@ or @toListOf l@. folding :: Foldable f => (s -> f a) -> Fold s t a b folding :: (s -> f a) -> Fold s t a b folding s -> f a sa = (s -> f a) -> LensLike f s t a b forall (g :: * -> *) (f :: * -> *) s a t b. (Foldable g, Phantom f, Applicative f) => (s -> g a) -> LensLike f s t a b LF.folding s -> f a sa -- | Returns a list of all of the referenced values in order. toListOf :: Fold s t a b -> s -> [a] toListOf :: Fold s t a b -> s -> [a] toListOf Fold s t a b l = FoldLike [a] s t a b -> s -> [a] forall a s t b. FoldLike [a] s t a b -> s -> [a] LF.toListOf FoldLike [a] s t a b Fold s t a b l -- | Returns true if all of the referenced values satisfy the given predicate. allOf :: Fold s t a b -> (a -> Bool) -> s -> Bool allOf :: Fold s t a b -> (a -> Bool) -> s -> Bool allOf Fold s t a b l = FoldLike All s t a b -> (a -> Bool) -> s -> Bool forall s t a b. FoldLike All s t a b -> (a -> Bool) -> s -> Bool LF.allOf FoldLike All s t a b Fold s t a b l -- | Returns true if any of the referenced values satisfy the given predicate. anyOf :: Fold s t a b -> (a -> Bool) -> s -> Bool anyOf :: Fold s t a b -> (a -> Bool) -> s -> Bool anyOf Fold s t a b l = FoldLike Any s t a b -> (a -> Bool) -> s -> Bool forall s t a b. FoldLike Any s t a b -> (a -> Bool) -> s -> Bool LF.anyOf FoldLike Any s t a b Fold s t a b l -- | Returns 'Just' the first referenced value. -- Returns 'Nothing' if there are no referenced values. -- See '^?' for an infix version of 'firstOf' firstOf :: Fold s t a b -> s -> Maybe a firstOf :: Fold s t a b -> s -> Maybe a firstOf Fold s t a b l = FoldLike (First a) s t a b -> s -> Maybe a forall a s t b. FoldLike (First a) s t a b -> s -> Maybe a LF.firstOf FoldLike (First a) s t a b Fold s t a b l -- | Returns 'Just' the last referenced value. -- Returns 'Nothing' if there are no referenced values. lastOf :: Fold s t a b -> s -> Maybe a lastOf :: Fold s t a b -> s -> Maybe a lastOf Fold s t a b l = FoldLike (Last a) s t a b -> s -> Maybe a forall a s t b. FoldLike (Last a) s t a b -> s -> Maybe a LF.lastOf FoldLike (Last a) s t a b Fold s t a b l -- | Returns the sum of all the referenced values. sumOf :: Num a => Fold s t a b -> s -> a sumOf :: Fold s t a b -> s -> a sumOf Fold s t a b l = FoldLike (Sum a) s t a b -> s -> a forall a s t b. Num a => FoldLike (Sum a) s t a b -> s -> a LF.sumOf FoldLike (Sum a) s t a b Fold s t a b l -- | Returns the product of all the referenced values. productOf :: Num a => Fold s t a b -> s -> a productOf :: Fold s t a b -> s -> a productOf Fold s t a b l = FoldLike (Product a) s t a b -> s -> a forall a s t b. Num a => FoldLike (Product a) s t a b -> s -> a LF.productOf FoldLike (Product a) s t a b Fold s t a b l -- | Counts the number of references in a traversal or fold for the input. lengthOf :: Num r => Fold s t a b -> s -> r lengthOf :: Fold s t a b -> s -> r lengthOf Fold s t a b l = FoldLike (Sum r) s t a b -> s -> r forall r s t a b. Num r => FoldLike (Sum r) s t a b -> s -> r LF.lengthOf FoldLike (Sum r) s t a b Fold s t a b l -- | Returns true if the number of references in the input is zero. nullOf :: Fold s t a b -> s -> Bool nullOf :: Fold s t a b -> s -> Bool nullOf Fold s t a b l = FoldLike All s t a b -> s -> Bool forall s t a b. FoldLike All s t a b -> s -> Bool LF.nullOf FoldLike All s t a b Fold s t a b l infixl 8 ^.. -- | Returns a list of all of the referenced values in order. (^..) :: s -> Fold s t a b -> [a] s x^.. :: s -> Fold s t a b -> [a] ^..Fold s t a b l = s x s -> FoldLike [a] s t a b -> [a] forall s a t b. s -> FoldLike [a] s t a b -> [a] LF.^.. FoldLike [a] s t a b Fold s t a b l infixl 8 ^? -- | Returns 'Just' the first referenced value. -- Returns 'Nothing' if there are no referenced values. (^?) :: s -> Fold s t a b -> Maybe a s x^? :: s -> Fold s t a b -> Maybe a ^?Fold s t a b l = s x s -> FoldLike (First a) s t a b -> Maybe a forall s a t b. s -> FoldLike (First a) s t a b -> Maybe a LF.^? FoldLike (First a) s t a b Fold s t a b l -- | Returns 'Right' of the first referenced value. -- Returns 'Left' the original value when there are no referenced values. -- In case there are no referenced values, the result might have a fresh type parameter, thereby proving the original value had no referenced values. matching :: Traversal s t a b -> s -> Either t a matching :: Traversal s t a b -> s -> Either t a matching Traversal s t a b l = LensLike (Either a) s t a b -> s -> Either t a forall a s t b. LensLike (Either a) s t a b -> s -> Either t a LF.matching LensLike (Either a) s t a b Traversal s t a b l zipWithOf :: Grate s t a b -> (a -> a -> b) -> s -> s -> t -- ^ Returns a binary instance of a grate. -- -- @ -- zipWithOf l f x y = degrating l (\k -> f (k x) (k y)) -- @ zipWithOf :: Grate s t a b -> (a -> a -> b) -> s -> s -> t zipWithOf Grate s t a b l = GrateLike (Prod Identity Identity) s t a b -> (a -> a -> b) -> s -> s -> t forall s t a b. GrateLike (Prod Identity Identity) s t a b -> (a -> a -> b) -> s -> s -> t LF.zipWithOf GrateLike (Prod Identity Identity) s t a b Grate s t a b l degrating :: Grate s t a b -> ((s -> a) -> b) -> t -- ^ Demote a grate to its normal, higher-order function, form. -- -- @ -- degrating . grate = id -- grate . degrating = id -- @ degrating :: Grate s t a b -> ((s -> a) -> b) -> t degrating Grate s t a b l = AGrate s t a b -> ((s -> a) -> b) -> t forall s t a b. AGrate s t a b -> ((s -> a) -> b) -> t LF.degrating AGrate s t a b Grate s t a b l -- | Demote a resetter to a semantic editor combinator. -- -- @ -- under :: Prism s t a b -> Traversal s t a b -- under :: Grid s t a b -> Traversal s t a b -- under :: Adapter s t a b -> Lens s t a b -- @ -- -- Covert an 'AdapterLike' optic into a 'LensLike' optic. -- -- Note: this function is unrelated to the lens package's @under@ function. under :: Resetter s t a b -> (a -> b) -> s -> t under :: Resetter s t a b -> (a -> b) -> s -> t under Resetter s t a b l = AResetter s t a b -> (a -> b) -> s -> t forall s t a b. AResetter s t a b -> (a -> b) -> s -> t LF.under AResetter s t a b Resetter s t a b l -- | Set all referenced fields to the given value. reset :: Resetter s t a b -> b -> s -> t reset :: Resetter s t a b -> b -> s -> t reset Resetter s t a b l = AResetter s t a b -> b -> s -> t forall s t a b. AResetter s t a b -> b -> s -> t LF.reset AResetter s t a b Resetter s t a b l -- | Demote a setter to a semantic editor combinator. -- -- @ -- over :: Prism s t a b -> Reviwer s t a b -- over :: Grid s t a b -> Grate s t a b -- over :: Adapter s t a b -> Grate s t a b -- @ -- -- Covert an 'AdapterLike' optic into a 'GrateLike' optic. over :: Setter s t a b -> (a -> b) -> s -> t over :: Setter s t a b -> (a -> b) -> s -> t over Setter s t a b l = ASetter s t a b -> (a -> b) -> s -> t forall s t a b. ASetter s t a b -> (a -> b) -> s -> t LF.over ASetter s t a b Setter s t a b l infixr 4 %~ -- | Modify all referenced fields. (%~) :: Setter s t a b -> (a -> b) -> s -> t Setter s t a b l %~ :: Setter s t a b -> (a -> b) -> s -> t %~ a -> b f = LensLike Identity s t a b Setter s t a b l LensLike Identity s t a b -> (a -> b) -> s -> t forall s t a b. ASetter s t a b -> (a -> b) -> s -> t LF.%~ a -> b f infixr 4 .~ -- | Set all referenced fields to the given value. (.~) :: Setter s t a b -> b -> s -> t Setter s t a b l .~ :: Setter s t a b -> b -> s -> t .~ b b = LensLike Identity s t a b Setter s t a b l LensLike Identity s t a b -> b -> s -> t forall s t a b. ASetter s t a b -> b -> s -> t LF..~ b b -- | Set all referenced fields to the given value. set :: Setter s t a b -> b -> s -> t set :: Setter s t a b -> b -> s -> t set Setter s t a b l = ASetter s t a b -> b -> s -> t forall s t a b. ASetter s t a b -> b -> s -> t LF.set ASetter s t a b Setter s t a b l infixr 4 +~, -~, *~ (+~), (-~), (*~) :: Num a => Setter s t a a -> a -> s -> t Setter s t a a l +~ :: Setter s t a a -> a -> s -> t +~ a a = LensLike Identity s t a a Setter s t a a l LensLike Identity s t a a -> a -> s -> t forall a s t. Num a => ASetter s t a a -> a -> s -> t LF.+~ a a Setter s t a a l -~ :: Setter s t a a -> a -> s -> t -~ a a = LensLike Identity s t a a Setter s t a a l LensLike Identity s t a a -> a -> s -> t forall a s t. Num a => ASetter s t a a -> a -> s -> t LF.-~ a a Setter s t a a l *~ :: Setter s t a a -> a -> s -> t *~ a a = LensLike Identity s t a a Setter s t a a l LensLike Identity s t a a -> a -> s -> t forall a s t. Num a => ASetter s t a a -> a -> s -> t LF.*~ a a infixr 4 //~ (//~) :: Fractional a => Setter s t a a -> a -> s -> t Setter s t a a l //~ :: Setter s t a a -> a -> s -> t //~ a a = LensLike Identity s t a a Setter s t a a l LensLike Identity s t a a -> a -> s -> t forall a s t. Fractional a => ASetter s t a a -> a -> s -> t LF.//~ a a infixr 4 &&~, ||~ (&&~), (||~) :: Setter s t Bool Bool -> Bool -> s -> t Setter s t Bool Bool l &&~ :: Setter s t Bool Bool -> Bool -> s -> t &&~ Bool a = LensLike Identity s t Bool Bool Setter s t Bool Bool l LensLike Identity s t Bool Bool -> Bool -> s -> t forall s t. ASetter s t Bool Bool -> Bool -> s -> t LF.&&~ Bool a Setter s t Bool Bool l ||~ :: Setter s t Bool Bool -> Bool -> s -> t ||~ Bool a = LensLike Identity s t Bool Bool Setter s t Bool Bool l LensLike Identity s t Bool Bool -> Bool -> s -> t forall s t. ASetter s t Bool Bool -> Bool -> s -> t LF.||~ Bool a infixr 4 <>~ -- | Monoidally append a value to all referenced fields. (<>~) :: (Monoid a) => Setter s t a a -> a -> s -> t Setter s t a a l <>~ :: Setter s t a a -> a -> s -> t <>~ a a = LensLike Identity s t a a Setter s t a a l LensLike Identity s t a a -> a -> s -> t forall a s t. Monoid a => ASetter s t a a -> a -> s -> t LF.<>~ a a