-- | This is the main module for end-users of lens-families-core. -- If you are not building your own lenses or traversals, but just using functional references made by others, this is the only module you need. module Lens.Family ( -- * Lenses -- -- | This module provides '^.' for accessing fields and '.~' and '%~' 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 '&' 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 => (b -> f b) -> a -> f a@ and lens families have type @'Functor' f => (b i -> f (b j)) -> a i -> f (a 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 b => LensLike' Maybe a b -> (b -> b) -> a -> a -- > sharedUpdate l f a = fromMaybe a (l f' a) -- > where -- > f' b | fb == b = Nothing -- > | otherwise = Just fb -- > where -- > fb = f b -- * Traversals -- -- | '^.' 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 '.~' is used with a traversal, all referenced fields will be set to the same value, and when '%~' is used with a traversal, all referenced fields will be modified with the same function. -- -- Like lenses, 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 => (b -> f b) -> a -> f a@ and traversal families have type @'Applicative' f => (b i -> f (b j)) -> a i -> f (a j)@. -- -- For stock lenses and traversals, see "Lens.Family.Stock". -- -- To build your own lenses and traversals, see "Lens.Family.Unchecked". -- -- 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> -- * Documentation to, view, (^.) , folding, views, (^..), (^?) , toListOf, allOf, anyOf, firstOf, lastOf, sumOf, productOf , lengthOf, nullOf , backwards , over, (%~), set, (.~) , (&) -- * Pseudo-imperatives , (+~), (*~), (-~), (//~), (&&~), (||~), (<>~) -- * Types , LensLike, LensLike' , FoldLike, FoldLike' , ASetter, ASetter' , Phantom , Constant, Identity -- * Re-exports , Applicative, Foldable, Monoid , Backwards, All, Any, First, Last, Sum, Product ) where import Control.Applicative (Applicative) import Control.Applicative.Backwards (Backwards(..)) import Data.Foldable (Foldable, traverse_) import Data.Functor.Identity (Identity(..)) import Data.Functor.Constant (Constant(..)) import Data.Monoid ( Monoid, mappend , All(..), Any(..) , First(..), Last(..) , Sum(..), Product(..) ) import Lens.Family.Phantom (Phantom, coerce) import Lens.Family.Unchecked ( LensLike, LensLike' ) type FoldLike r a a' b b' = LensLike (Constant r) a a' b b' type FoldLike' r a b = LensLike' (Constant r) a b type ASetter a a' b b' = LensLike Identity a a' b b' type ASetter' a b = LensLike' Identity a b to :: Phantom f => (a -> b) -> LensLike f a a' b b' -- ^ @ -- to :: (a -> b) -> Getter a a' b b' -- @ -- -- '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 p f = coerce . f . p view :: FoldLike b a a' b b' -> a -> b -- ^ @ -- view :: Getter a a' b b' -> a -> b -- @ -- -- Demote a lens or getter to a projection function. -- -- @ -- view :: Monoid b => Fold a a' b b' -> a -> b -- @ -- -- Returns the monoidal summary of a traversal or a fold. view l = (^.l) folding :: (Foldable g, Phantom f, Applicative f) => (a -> g b) -> LensLike f a a' b b' -- ^ @ -- folding :: (a -> [b]) -> Fold a a' b b' -- @ -- -- '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 p f = coerce . traverse_ f . p views :: FoldLike r a a' b b' -> (b -> r) -> a -> r -- ^ @ -- views :: Monoid r => Fold a a' b b' -> (b -> r) -> a -> r -- @ -- -- Given a fold or traversal, return the 'foldMap' of all the values using the given function. -- -- @ -- views :: Getter a a' b b' -> (b -> r) -> a -> r -- @ -- -- 'views' is not particularly useful for getters or lenses, but given a getter or lens, it returns the referenced value passed through the given function. -- -- @ -- views l f a = f (view l a) -- @ views l f = getConstant . l (Constant . f) toListOf :: FoldLike [b] a a' b b' -> a -> [b] -- ^ @ -- toListOf :: Fold a a' b b' -> a -> [b] -- @ -- -- Returns a list of all of the referenced values in order. toListOf l = views l (:[]) allOf :: FoldLike All a a' b b' -> (b -> Bool) -> a -> Bool -- ^ @ -- allOf :: Fold a a' b b' -> (b -> Bool) -> a -> Bool -- @ -- -- Returns true if all of the referenced values satisfy the given predicate. allOf l p = getAll . views l (All . p) anyOf :: FoldLike Any a a' b b' -> (b -> Bool) -> a -> Bool -- ^ @ -- anyOf :: Fold a a' b b' -> (b -> Bool) -> a -> Bool -- @ -- -- Returns true if any of the referenced values satisfy the given predicate. anyOf l p = getAny . views l (Any . p) firstOf :: FoldLike (First b) a a' b b' -> a -> Maybe b -- ^ @ -- firstOf :: Fold a a' b b' -> a -> Maybe b -- @ -- -- Returns 'Just' the first referenced value. -- Returns 'Nothing' if there are no referenced values. -- See '^?' for an infix version of 'firstOf' firstOf l = getFirst . views l (First . Just) lastOf :: FoldLike (Last b) a a' b b' -> a -> Maybe b -- ^ @ -- lastOf :: Fold a a' b b' -> a -> Maybe b -- @ -- -- Returns 'Just' the last referenced value. -- Returns 'Nothing' if there are no referenced values. lastOf l = getLast . views l (Last . Just) sumOf :: Num b => FoldLike (Sum b) a a' b b' -> a -> b -- ^ @ -- sumOf :: Num b => Fold a a' b b' -> a -> b -- @ -- -- Returns the sum of all the referenced values. sumOf l = getSum . views l Sum productOf :: Num b => FoldLike (Product b) a a' b b' -> a -> b -- ^ @ -- productOf :: Num b => Fold a a' b b' -> a -> b -- @ -- -- Returns the product of all the referenced values. productOf l = getProduct . views l Product lengthOf :: Num r => FoldLike (Sum r) a a' b b' -> a -> r -- ^ @ -- lengthOf :: Num r => Fold a a' b b' -> a -> r -- @ -- -- Counts the number of references in a traversal or fold for the input. lengthOf l = getSum . views l (const (Sum 1)) nullOf :: FoldLike All a a' b b' -> a -> Bool -- ^ @ -- nullOf :: Fold a a' b b' -> a -> Bool -- @ -- -- Returns true if the number of references in the input is zero. nullOf l = allOf l (const False) infixr 8 ^. (^.) :: a -> FoldLike b a a' b b' -> b -- ^ @ -- (^.) :: a -> Getter a a' b b' -> b -- @ -- -- Access the value referenced by a getter or lens. -- -- @ -- (^.) :: Monoid b => a -> Fold a a' b b' -> b -- @ -- -- Access the monoidal summary referenced by a getter or lens. x^.l = getConstant $ l Constant x infixr 8 ^.. (^..) :: a -> FoldLike [b] a a' b b' -> [b] -- ^ @ -- (^..) :: a -> Getter a a' b b' -> [b] -- @ -- -- Returns a list of all of the referenced values in order. x^..l = toListOf l x infixr 8 ^? (^?) :: a -> FoldLike (First b) a a' b b' -> Maybe b -- ^ @ -- (^?) :: a -> Fold a a' b b' -> Maybe b -- @ -- -- Returns 'Just' the first referenced value. -- Returns 'Nothing' if there are no referenced values. x^?l = firstOf l x backwards :: LensLike (Backwards f) a a' b b' -> LensLike f a a' b b' -- ^ @ -- backwards :: Traversal a a' b b' -> Traversal a a' b b' -- backwards :: Fold a a' b b' -> Fold a a' b b' -- @ -- -- Given a traversal or fold, reverse the order that elements are traversed. -- -- @ -- backwards :: Lens a a' b b' -> Lens a a' b b' -- backwards :: Getter a a' b b' -> Getter a a' b b' -- backwards :: Setter a a' b b' -> Setter a a' b b' -- @ -- -- No effect on lenses, getters or setters. backwards l f = forwards . l (Backwards . f) -- | Demote a setter to a semantic editor combinator. over :: ASetter a a' b b' -> (b -> b') -> a -> a' over l = (l %~) infixr 4 %~ -- | Modify all referenced fields. (%~) :: ASetter a a' b b' -> (b -> b') -> a -> a' l %~ f = runIdentity . l (Identity . f) infixr 4 .~ -- | Set all referenced fields to the given value. (.~) :: ASetter a a' b b' -> b' -> a -> a' l .~ b = l %~ const b -- | Set all referenced fields to the given value. set :: ASetter a a' b b' -> b' -> a -> a' set = (.~) infixl 1 & -- | A flipped version of @($)@. (&) :: a -> (a -> b) -> b (&) = flip ($) infixr 4 +~, -~, *~ (+~), (-~), (*~) :: Num b => ASetter' a b -> b -> a -> a f +~ b = f %~ (+ b) f -~ b = f %~ subtract b f *~ b = f %~ (* b) infixr 4 //~ (//~) :: Fractional b => ASetter' a b -> b -> a -> a f //~ b = f %~ (/ b) infixr 4 &&~, ||~ (&&~), (||~) :: ASetter' a Bool -> Bool -> a -> a f &&~ b = f %~ (&& b) f ||~ b = f %~ (|| b) infixr 4 <>~ -- | Monoidally append a value to all referenced fields. (<>~) :: (Monoid o) => ASetter' a o -> o -> a -> a f <>~ o = f %~ (`mappend` o)