lens-family 0.1.0 → 1.0.0
raw patch · 7 files changed
+492/−133 lines, 7 filesdep ~lens-family-core
Dependency ranges changed: lens-family-core
Files
- CHANGELOG +5/−0
- lens-family.cabal +11/−7
- src/Lens/Family2.hs +176/−3
- src/Lens/Family2/State/Lazy.hs +77/−28
- src/Lens/Family2/State/Strict.hs +77/−28
- src/Lens/Family2/Stock.hs +69/−34
- src/Lens/Family2/Unchecked.hs +77/−33
CHANGELOG view
@@ -1,3 +1,8 @@+1.0.0 (Changes from 0.1.0)+=========================+* added support for folds and traversals+* renamed all functions to be mostly compatible with the lexicon from lens.+ 0.1.0 (Changes from 0.0.1) ========================= * added project and sec
lens-family.cabal view
@@ -1,30 +1,34 @@ name: lens-family category: Data, Lenses-version: 0.1.0+version: 1.0.0 license: BSD3 cabal-version: >= 1.6 license-file: LICENSE author: Russell O'Connor maintainer: Russell O'Connor <roconnor@theorem.ca>-stability: expermimental-copyright: Copyright (C) 2012 Russell O'Connor+stability: experimental+copyright: Copyright (C) 2012,2013 Russell O'Connor synopsis: Lens Families description: Lens Families build-type: Simple extra-source-files: CHANGELOG-description: This package provides optimal first class functional references+description: This package provides first class functional references. In addition to the usual operations of getting, setting and composition, plus integration with monad state, lens families provide some unique features: . * Polymorphic updating .+ * Traversals+ . * Cast projection functions to read-only lenses .- * Cast semantic editor combinators to modify-only lenses+ * Cast \"toList\" functions to read-only traversals+ .+ * Cast semantic editor combinators to modify-only traversals. source-repository head type: darcs location: http://r6.ca/lens-family- + library extensions: Rank2Types build-depends:@@ -32,7 +36,7 @@ containers >= 0.3 && < 0.6, transformers >= 0.2.0 && < 0.4, mtl >= 2.1 && < 2.2,- lens-family-core >= 0.1 && < 0.2+ lens-family-core >= 1.0 && < 1.1 exposed-modules: Lens.Family2.Unchecked
src/Lens/Family2.hs view
@@ -1,5 +1,178 @@-module Lens.Family2- ( module Lens.Family+{-# LANGUAGE Rank2Types #-}+-- | This is the main module for end-users of lens-families.+-- 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.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 => (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+--+-- | '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 traverasal.+-- '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 traveral, 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.+--+-- 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.Family2.Stock".+--+-- To build your own lenses and traversals, see "Lens.Family2.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, LF.view, (LF.^.)+ , folding, LF.views, (^..), (^?)+ , toListOf, allOf, anyOf, firstOf, lastOf, sumOf, productOf+ , lengthOf, nullOf+ , LF.backwards+ , LF.over, (LF.%~), LF.set, (LF..~)+ , (LF.&)+ -- * Pseudo-imperatives+ , (LF.+~), (LF.*~), (LF.-~), (LF.//~), (LF.&&~), (LF.||~), (LF.<>~)+ -- * Types+ , Lens, Lens'+ , Traversal, Traversal'+ , Getter, Getter'+ , Fold, Fold'+ , LF.Setter, LF.Setter'+ , LF.LensLike, LF.LensLike'+ , LF.FoldLike, LF.FoldLike'+ , LF.Getting, LF.Setting+ , LF.Phantom+-- * Re-exports+ , Applicative, Foldable, Monoid+ , LF.Backwards ) where -import Lens.Family+import Control.Applicative (Applicative)+import Data.Foldable (Foldable)+import Data.Monoid (Monoid)+import qualified Lens.Family as LF+import Lens.Family2.Unchecked (Lens, Lens', Traversal, Traversal')++type Fold a a' b b' = forall f. (LF.Phantom f, Applicative f) => LF.LensLike f a a' b b'+type Fold' a b = Fold a a b b++type Getter a a' b b' = forall f. LF.Phantom f => LF.LensLike f a a' b b'+type Getter' a b = Fold 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 :: (a -> b) -> Getter a a' b b'+to = LF.to++-- | '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 => (a -> f b) -> Fold a a' b b'+folding = LF.folding++-- | Returns a list of all of the referenced values in order.+toListOf :: Fold a a' b b' -> a -> [b]+toListOf l = LF.toListOf l++-- | Returns true if all of the referenced values satisfy the given predicate.+allOf :: Fold a a' b b' -> (b -> Bool) -> a -> Bool+allOf l = LF.allOf l++anyOf :: Fold a a' b b' -> (b -> Bool) -> a -> Bool+anyOf l = LF.anyOf l++-- | Returns 'Just' the first referenced value.+-- Returns 'Nothing' if there are no referenced values.+-- See '^?' for an infix version of 'firstOf'+firstOf :: Fold a a' b b' -> a -> Maybe b+firstOf l = LF.firstOf l++-- | Returns 'Just' the last referenced value.+-- Returns 'Nothing' if there are no referenced values.+lastOf :: Fold a a' b b' -> a -> Maybe b+lastOf l = LF.lastOf l++-- | Returns the sum of all the referenced values.+sumOf :: Num b => Fold a a' b b' -> a -> b+sumOf l = LF.sumOf l++-- | Returns the product of all the referenced values.+productOf :: Num b => Fold a a' b b' -> a -> b+productOf l = LF.productOf l++-- | Counts the number of references in a traversal or fold for the input.+lengthOf :: Num r => Fold a a' b b' -> a -> r+lengthOf l = LF.lengthOf l++-- | Returns true if the number of references in the input is zero.+nullOf :: Fold a a' b b' -> a -> Bool+nullOf l = LF.nullOf l++infixr 8 ^..++-- | Returns a list of all of the referenced values in order.+(^..) :: a -> Fold a a' b b' -> [b]+x^..l = x LF.^.. l++infixr 8 ^?++-- | Returns 'Just' the first referenced value.+-- Returns 'Nothing' if there are no referenced values.+(^?) :: a -> Fold a a' b b' -> Maybe b+x^?l = x LF.^? l
src/Lens/Family2/State/Lazy.hs view
@@ -1,73 +1,122 @@ {-# LANGUAGE Rank2Types #-} -- | Lenses allow you to use fields of the state of a state monad as if they were variables in an imperative language.--- 'access' is used to retrieve the value of a variable, and '~=' and '%=' allow you to set and modify a variable.+-- 'use' is used to retrieve the value of a variable, and '.=' and '%=' allow you to set and modify a variable. -- C-style compound assignments are also provided. module Lens.Family2.State.Lazy- ( focus- , access+ ( LFS.zoom+ , use, uses , (%=)- , (~=)+ , assign, (.=) , (%%=)- -- * Compound Assignments+-- * Compound Assignments , (+=), (-=), (*=) , (//=) , (&&=), (||=) , (<>=)+-- * Types+ , LFS.Zooming+-- * Re-exports+ , LensLike, LensLike'+ , FoldLike+ , Setter, Setter'+ , LFS.StateT, MonadState, Writer+ , Monoid ) where import Data.Monoid (Monoid, mappend)+import Data.Tuple (swap) import Control.Monad (liftM)-import Control.Monad.State.Lazy (MonadState, StateT(..), get, modify, state)-import Lens.Family (Getter, Setter, (^.), (%~))+import Control.Monad.Trans.Writer.Lazy (Writer, writer, runWriter)+import Control.Monad.State.Lazy (MonadState, get, modify, state)+import Lens.Family2 ( LensLike, LensLike'+ , FoldLike+ , Setter, Setter'+ , view, views, (%~)+ ) import qualified Lens.Family.State.Lazy as LFS-import Lens.Family2.Stock (Lens) --- | Lift a stateful operation on a field to a stateful operation on the whole state.--- This is a good way to call a \"subroutine\" that only needs access to part of the state.-focus :: Monad m => Lens a b -> StateT b m c -> StateT a m c-focus l = LFS.focus l+use :: MonadState a m => FoldLike b a a' b b' -> m b+-- ^ @+-- use :: MonadState a m => Getter a a' b b' -> m b+-- @+--+-- Retrieve a field of the state+--+-- @+-- use :: (Monoid b, MonadState a m) => Fold a a' b b' -> m b+-- @+--+-- Retrieve a monoidal summary of all the referenced fields from the state+use l = view l `liftM` get --- | Retrieve a field of the state-access :: MonadState a m => Getter a b -> m b-access l = (^. l) `liftM` get+uses :: MonadState a m => FoldLike r a a' b b' -> (b -> r) -> m r+-- ^ @+-- uses :: (MonadState a m, Monoid r) => Fold a a' b b' -> (b -> r) -> m r+-- @+--+-- Retrieve all the referenced fields from the state and foldMap the results together with @f :: b -> r@.+--+-- @+-- uses :: MonadState a m => Getter a a' b b' -> (b -> r) -> m r+-- @+--+-- Retrieve a field of the state and pass it through the function @f :: b -> r@.+--+-- @uses l f = f <$> use l@+uses l f = views l f `liftM` get infix 4 %= --- | Modify a field of the state-(%=) :: MonadState a m => Setter a b -> (b -> b) -> m ()+-- | Modify a field of the state.+(%=) :: MonadState a m => Setter a a b b' -> (b -> b') -> m () l %= f = modify (l %~ f) -infix 4 ~=+infix 4 .= --- | Set a field of the state-(~=) :: MonadState a m => Setter a b -> b -> m ()-l ~= v = l %= const v+-- | Set a field of the state.+(.=) :: MonadState a m => Setter a a b b' -> b' -> m ()+l .= v = l %= const v +-- | Set a field of the state.+assign :: MonadState a m => Setter a a b b' -> b' -> m ()+assign = (.=)+ infix 4 %%= --- | Modify a field of the state while returning another value-(%%=) :: MonadState a m => Lens a b -> (b -> (c, b)) -> m c-l %%= f = state (l f)+(%%=) :: MonadState a m => LensLike (Writer c) a a b b' -> (b -> (c, b')) -> m c+-- ^ @+-- (%%=) :: MonadState a m => Lens a a b b' -> (b -> (c, b')) -> m c+-- @+--+-- Modify a field of the state while returning another value.+--+-- @+-- (%%=) :: (MonadState a m, Monoid c) => Traversal a a b b' -> (b -> (c, b')) -> m c+-- @+--+-- Modify each field of the state and return the 'mconcat' of the other values.+l %%= f = state (swap . runWriter . l (writer . swap . f)) infixr 4 +=, -=, *= -(+=), (-=), (*=) :: (MonadState a m, Num b) => Setter a b -> b -> m ()+(+=), (-=), (*=) :: (MonadState a m, Num b) => Setter' a b -> b -> m () f += b = f %= (+ b) f -= b = f %= subtract b f *= b = f %= (* b) infixr 4 //= -(//=) :: (MonadState a m, Fractional b) => Setter a b -> b -> m ()+(//=) :: (MonadState a m, Fractional b) => Setter' a b -> b -> m () f //= b = f %= (/ b) infixr 4 &&=, ||= -(&&=), (||=) :: MonadState a m => Setter a Bool -> Bool -> m ()+(&&=), (||=) :: MonadState a m => Setter' a Bool -> Bool -> m () f &&= b = f %= (&& b) f ||= b = f %= (|| b) infixr 4 <>= -(<>=) :: (Monoid o, MonadState a m) => Setter a o -> o -> m ()+-- | Monoidally append a value to all referenced fields of the state.+(<>=) :: (Monoid o, MonadState a m) => Setter' a o -> o -> m () f <>= b = f %= (`mappend` b)
src/Lens/Family2/State/Strict.hs view
@@ -1,73 +1,122 @@ {-# LANGUAGE Rank2Types #-} -- | Lenses allow you to use fields of the state of a state monad as if they were variables in an imperative language.--- 'access' is used to retrieve the value of a variable, and '~=' and '%=' allow you to set and modify a variable.+-- 'use' is used to retrieve the value of a variable, and '.=' and '%=' allow you to set and modify a variable. -- C-style compound assignments are also provided. module Lens.Family2.State.Strict- ( focus- , access+ ( LFS.zoom+ , use, uses , (%=)- , (~=)+ , assign, (.=) , (%%=)- -- * Compound Assignments+-- * Compound Assignments , (+=), (-=), (*=) , (//=) , (&&=), (||=) , (<>=)+-- * Types+ , LFS.Zooming+-- * Re-exports+ , LensLike, LensLike'+ , FoldLike+ , Setter, Setter'+ , LFS.StateT, MonadState, Writer+ , Monoid ) where import Data.Monoid (Monoid, mappend)+import Data.Tuple (swap) import Control.Monad (liftM)-import Control.Monad.State.Strict (MonadState, StateT(..), get, modify, state)-import Lens.Family (Getter, Setter, (^.), (%~))+import Control.Monad.Trans.Writer.Lazy (Writer, writer, runWriter)+import Control.Monad.State.Strict (MonadState, get, modify, state)+import Lens.Family2 ( LensLike, LensLike'+ , FoldLike+ , Setter, Setter'+ , view, views, (%~)+ ) import qualified Lens.Family.State.Strict as LFS-import Lens.Family2.Stock (Lens) --- | Lift a stateful operation on a field to a stateful operation on the whole state.--- This is a good way to call a \"subroutine\" that only needs access to part of the state.-focus :: Monad m => Lens a b -> StateT b m c -> StateT a m c-focus l = LFS.focus l+use :: MonadState a m => FoldLike b a a' b b' -> m b+-- ^ @+-- use :: MonadState a m => Getter a a' b b' -> m b+-- @+--+-- Retrieve a field of the state+--+-- @+-- use :: (Monoid b, MonadState a m) => Fold a a' b b' -> m b+-- @+--+-- Retrieve a monoidal summary of all the referenced fields from the state+use l = view l `liftM` get --- | Retrieve a field of the state-access :: MonadState a m => Getter a b -> m b-access l = (^. l) `liftM` get+uses :: MonadState a m => FoldLike r a a' b b' -> (b -> r) -> m r+-- ^ @+-- uses :: (MonadState a m, Monoid r) => Fold a a' b b' -> (b -> r) -> m r+-- @+--+-- Retrieve all the referenced fields from the state and foldMap the results together with @f :: b -> r@.+--+-- @+-- uses :: MonadState a m => Getter a a' b b' -> (b -> r) -> m r+-- @+--+-- Retrieve a field of the state and pass it through the function @f :: b -> r@.+--+-- @uses l f = f <$> use l@+uses l f = views l f `liftM` get infix 4 %= --- | Modify a field of the state-(%=) :: MonadState a m => Setter a b -> (b -> b) -> m ()+-- | Modify a field of the state.+(%=) :: MonadState a m => Setter a a b b' -> (b -> b') -> m () l %= f = modify (l %~ f) -infix 4 ~=+infix 4 .= --- | Set a field of the state-(~=) :: MonadState a m => Setter a b -> b -> m ()-l ~= v = l %= const v+-- | Set a field of the state.+(.=) :: MonadState a m => Setter a a b b' -> b' -> m ()+l .= v = l %= const v +-- | Set a field of the state.+assign :: MonadState a m => Setter a a b b' -> b' -> m ()+assign = (.=)+ infix 4 %%= --- | Modify a field of the state while returning another value-(%%=) :: MonadState a m => Lens a b -> (b -> (c, b)) -> m c-l %%= f = state (l f)+(%%=) :: MonadState a m => LensLike (Writer c) a a b b' -> (b -> (c, b')) -> m c+-- ^ @+-- (%%=) :: MonadState a m => Lens a a b b' -> (b -> (c, b')) -> m c+-- @+--+-- Modify a field of the state while returning another value.+--+-- @+-- (%%=) :: (MonadState a m, Monoid c) => Traversal a a b b' -> (b -> (c, b')) -> m c+-- @+--+-- Modify each field of the state and return the 'mconcat' of the other values.+l %%= f = state (swap . runWriter . l (writer . swap . f)) infixr 4 +=, -=, *= -(+=), (-=), (*=) :: (MonadState a m, Num b) => Setter a b -> b -> m ()+(+=), (-=), (*=) :: (MonadState a m, Num b) => Setter' a b -> b -> m () f += b = f %= (+ b) f -= b = f %= subtract b f *= b = f %= (* b) infixr 4 //= -(//=) :: (MonadState a m, Fractional b) => Setter a b -> b -> m ()+(//=) :: (MonadState a m, Fractional b) => Setter' a b -> b -> m () f //= b = f %= (/ b) infixr 4 &&=, ||= -(&&=), (||=) :: MonadState a m => Setter a Bool -> Bool -> m ()+(&&=), (||=) :: MonadState a m => Setter' a Bool -> Bool -> m () f &&= b = f %= (&& b) f ||= b = f %= (|| b) infixr 4 <>= -(<>=) :: (Monoid o, MonadState a m) => Setter a o -> o -> m ()+-- | Monoidally append a value to all referenced fields of the state.+(<>=) :: (Monoid o, MonadState a m) => Setter' a o -> o -> m () f <>= b = f %= (`mappend` b)
src/Lens/Family2/Stock.hs view
@@ -1,56 +1,91 @@ {-# LANGUAGE Rank2Types #-}--- | This module contains lenses for common structures in Haskell.--- It also contains the lens combinators 'mergeL' and '***'.-module Lens.Family2.Stock- ( -- * Lens Combinators- Stock.mergeL- , (***)- -- * Stock Lenses- , fstL, sndL- , funL- , mapL, intMapL- , setL, intSetL- -- * Types- , LensFamily, Lens+-- | This module contains lenses and traversals for common structures in Haskell.+-- It also contains the combinators for lenses and traversals.+module Lens.Family2.Stock (+-- * Lens Combinators+ Stock.choosing+ , Stock.alongside+ , Stock.beside+-- * Stock Lenses+ , _1, _2, both+ , chosen+ , ix+ , at, intAt+ , contains, intContains+-- * Stock Traversals+ , _Left, _Right+ , _Just, _Nothing+ , ignored+-- * Types+ , Stock.AlongsideLeft, Stock.AlongsideRight+-- * Re-exports+ , Lens, Lens'+ , Traversal, Traversal'+ , Stock.LensLike, Stock.LensLike'+ , Stock.Applicative ) where -import Lens.Family2.Unchecked (LensFamily, Lens) import qualified Lens.Family.Stock as Stock-import Lens.Family ((^.), (<~))+import Lens.Family2 ( Lens, Lens'+ , Traversal, Traversal'+ ) import qualified Data.Map as Map import qualified Data.IntMap as IntMap import qualified Data.Set as Set import qualified Data.IntSet as IntSet --- I suspect there is a more clever way to define this function.--- | Given two lens families, make a new lens on their product.-(***) :: LensFamily a1 a1' b1 b1' -> LensFamily a2 a2' b2 b2' -> LensFamily (a1, a2) (a1', a2') (b1, b2) (b1', b2')-(***) l1 l2 f (a1, a2) = (\(v'1, v'2) -> (l1 <~ v'1 $ a1, l2 <~ v'2 $ a2)) `fmap` f (a1 ^. l1, a2 ^. l2)- -- | Lens on the first element of a pair.-fstL :: LensFamily (a, b) (a', b) a a'-fstL = Stock.fstL+_1 :: Lens (a, b) (a', b) a a'+_1 = Stock._1 -- | Lens on the second element of a pair.-sndL :: LensFamily (a, b) (a, b') b b'-sndL = Stock.sndL+_2 :: Lens (a, b) (a, b') b b'+_2 = Stock._2 +-- | Lens on the Left or Right element of an ('Either' a a).+chosen :: Lens (Either a a) (Either b b) a b+chosen = Stock.chosen+ -- | Lens on a given point of a function.-funL :: (Eq k) => k -> Lens (k -> v) v-funL = Stock.funL+ix :: (Eq k) => k -> Lens' (k -> v) v+ix = Stock.ix -- | Lens on a given point of a 'Map.Map'.-mapL :: (Ord k) => k -> Lens (Map.Map k v) (Maybe v)-mapL = Stock.mapL+at :: (Ord k) => k -> Lens' (Map.Map k v) (Maybe v)+at = Stock.at -- | Lens on a given point of a 'IntMap.IntMap'.-intMapL :: Int -> Lens (IntMap.IntMap v) (Maybe v)-intMapL = Stock.intMapL+intAt :: Int -> Lens' (IntMap.IntMap v) (Maybe v)+intAt = Stock.intAt -- | Lens on a given point of a 'Set.Set'.-setL :: (Ord k) => k -> Lens (Set.Set k) Bool-setL = Stock.setL+contains :: (Ord k) => k -> Lens' (Set.Set k) Bool+contains = Stock.contains -- | Lens on a given point of a 'IntSet.IntSet'.-intSetL :: Int -> Lens IntSet.IntSet Bool-intSetL = Stock.intSetL+intContains :: Int -> Lens' IntSet.IntSet Bool+intContains = Stock.intContains++-- | Traversal on the 'Left' element of an 'Either'.+_Left :: Traversal (Either a b) (Either a' b) a a'+_Left = Stock._Left++-- | Traversal on the 'Right' element of an 'Either'.+_Right :: Traversal (Either a b) (Either a b') b b'+_Right = Stock._Right++-- | Traversal on the 'Just' element of a 'Maybe'.+_Just :: Traversal (Maybe a) (Maybe a') a a'+_Just = Stock._Just++-- | Traversal on the 'Nothing' element of a 'Maybe'.+_Nothing :: Traversal' (Maybe a) ()+_Nothing = Stock._Nothing++-- | Traversals on both elements of a pair @(a,a)@.+both :: Traversal (a,a) (b,b) a b+both = Stock.both++-- | The empty traveral on any type.+ignored :: Traversal a a b b'+ignored = Stock.ignored
src/Lens/Family2/Unchecked.hs view
@@ -1,22 +1,23 @@ {-# LANGUAGE Rank2Types #-} -- | /Caution/: Improper use of this module can lead to unexpected behaviour if the preconditions of the functions are not met.--- --- A lens family is created by separating a substructure from the rest of its structure by a functor.+module Lens.Family2.Unchecked (+-- * Lenses+-- | A lens family is created by separating a substructure from the rest of its structure by a functor. -- How to create a lens family is best illustrated by the common example of a field of a record: -- -- > data MyRecord a = MyRecord { _myA :: a, _myB :: Int } -- > -- > -- The use of type variables a and a' allow for polymorphic updates.--- > myA :: LensFamily (MyRecord a) (MyRecord a') a a'+-- > myA :: Lens (MyRecord a) (MyRecord a') a a' -- > myA f (MyRecord a b) = (\a' -> MyRecord a' b) `fmap` (f a) -- >--- > -- The field _myB is monomorphic, so we can use a plain Lens type.--- > -- However, the structure of the function is exactly the same as for LensFamily.--- > myB :: Lens (MyRecord a) Int+-- > -- The field _myB is monomorphic, so we can use a 'Lens'' type.+-- > -- However, the structure of the function is exactly the same as for Lens.+-- > myB :: Lens' (MyRecord a) Int -- > myB f (MyRecord a b) = (\b' -> MyRecord a b') `fmap` (f b) -- -- By following this template you can safely build your own lenses.--- To use this template, you do not need anything from this module other than the type synonyms 'LensFamily' and 'Lens', and even they are optional.+-- To use this template, you do not need anything from this module other than the type synonyms 'Lens' and 'Lens'', and even they are optional. -- See the @lens-family-th@ package to generate this code using Template Haskell. -- -- /Note/: It is possible to build lenses without even depending on @lens-family@ by expanding away the type synonym.@@ -26,33 +27,76 @@ -- > myA f (MyRecord a b) = (\a' -> MyRecord a' b) `fmap` (f a) -- -- You can build lenses for more than just fields of records.--- Any value @lens :: LensFamily a a' b b'@ is well-defined when it satisfies the two van Laarhoven lens laws:+-- Any value @l :: Lens a a' b b'@ is well-defined when it satisfies the two van Laarhoven lens laws: ----- * @lens Identity === Identity@+-- * @l Identity === Identity@ ----- * @--- lens (composeCoalgebroid f g) === composeCoalgebroid (lens f) (lens g)--- where--- composeCoalgebroid :: (Functor f, Functor g) => (b -> f c) -> (a -> g b) -> a -> (Compose g f) c--- composeCoalgebroid f g a = Compose $ f \`fmap\` g a === id--- @+-- * @l (Compose . fmap f . g) === Compose . fmap (l f) . (l g)@ ----- The functions 'mkLens' and 'mkIsoLens' can also be used to construct lenses.+-- The functions 'lens' and 'iso' can also be used to construct lenses. -- The resulting lenses will be well-defined so long as their preconditions are satisfied.-module Lens.Family2.Unchecked- ( mkLens- , mkIsoLens- , LF.Setting, LF.setting- -- * Types- , LensFamily, Lens- , LF.SetterFamily, LF.Setter++-- * Traversals+--+-- | If you have zero or more fields of the same type of a record, a traversal can be used to refer to all of them in order.+-- Multiple references are made by replacing the 'Functor' constraint of lenses with an 'Control.Applicative.Applicative' constraint.+-- Consider the following example of a record with two 'Int' fields.+--+-- > data MyRecord = MyRecord { _myA :: Int, _myB :: Int }+-- >+-- > -- myInts is a traversal over both fields of MyRecord.+-- > myInts :: Traversal' MyRecord Int+-- > myInts f (MyRecord a b) = MyRecord <$> f a <*> f b+--+-- If the record and the referenced fields are parametric, you can can build traversals with polymorphic updating.+-- Consider the following example of a record with two 'Maybe' fields.+--+-- > data MyRecord a = MyRecord { _myA :: Maybe a, _myB :: Maybe a }+-- >+-- > -- myInts is a traversal over both fields of MyRecord.+-- > myMaybes :: Traversal (MyRecord a) (MyRecord a') (Maybe a) (Maybe a')+-- > myMaybes f (MyRecord a b) = MyRecord <$> f a <*> f b+--+-- /Note/: As with lenses, is possible to build traversals without even depending on @lens-family-core@ by expanding away the type synonym.+--+-- > -- A traversal definition that only requires the Haskell "Prelude".+-- > myMaybes :: Applicative f => (Maybe a -> f (Maybe a')) -> MyRecord a -> f (MyRecord a')+-- > myMaybes f (MyRecord a b) = MyRecord <$> f a <*> f b+--+-- Unfortuantely, there are no helper functions for making traversals.+-- You must make them by hand.+--+-- Any value @t :: Traversal a a' b b'@ is well-defined when it satisfies the two van Laarhoven traversal laws:+--+-- * @t Identity === Identity@+--+-- * @t (Compose . fmap f . g) === Compose . fmap (t f) . (t g)@+--+-- 'Data.Traversable.traverse' is the canonical traversal for various containers.++-- * Documentation+ lens+ , iso+ , LF.setting+-- * Types+ , Lens, Lens'+ , Traversal, Traversal'+ , LF.Setting+ , LF.LensLike, LF.LensLike'+ , LF.Setter, LF.Setter'+-- * Re-exports+ , Applicative ) where +import Control.Applicative (Applicative) import qualified Lens.Family.Unchecked as LF -type LensFamily a a' b b' = forall f. Functor f => LF.RefFamily f a a' b b'-type Lens a b = LensFamily a a b b+type Lens a a' b b' = forall f. Functor f => LF.LensLike f a a' b b'+type Lens' a b = Lens a a b b +type Traversal a a' b b' = forall f. Applicative f => LF.LensLike f a a' b b'+type Traversal' a b = Traversal a a b b+ -- | Build a lens from a @getter@ and @setter@ families. -- -- /Caution/: In order for the generated lens family to be well-defined, you must ensure that the three lens laws hold:@@ -62,10 +106,10 @@ -- * @setter a (getter a) === a@ -- -- * @setter (setter a b1) b2) === setter a b2@-mkLens :: (a -> b) -- ^ getter- -> (a -> b' -> a') -- ^ setter- -> LensFamily a a' b b'-mkLens = LF.mkLens+lens :: (a -> b) -- ^ getter+ -> (a -> b' -> a') -- ^ setter+ -> Lens a a' b b'+lens = LF.lens -- | Build a lens from isomorphism families. --@@ -74,7 +118,7 @@ -- * @yin . yang === id@ -- -- * @yang . yin === id@-mkIsoLens :: (a -> b) -- ^ yin- -> (b' -> a') -- ^ yang- -> LensFamily a a' b b'-mkIsoLens = LF.mkIsoLens+iso :: (a -> b) -- ^ yin+ -> (b' -> a') -- ^ yang+ -> Lens a a' b b'+iso = LF.iso