Safe Haskell | Safe-Infered |
---|
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. 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 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 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.
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.
-- A lens definition that only requires the Haskell "Prelude". myA :: Functor f => (a -> f a') -> (MyRecord a) -> f (MyRecord a') 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:
lens 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
The functions mkLens
and mkIsoLens
can also be used to construct lenses.
The resulting lenses will be well-defined so long as their preconditions are satisfied.
- mkLens :: (a -> b) -> (a -> b' -> a') -> LensFamily a a' b b'
- mkIsoLens :: (a -> b) -> (b' -> a') -> LensFamily a a' b b'
- data Setting a
- setting :: ((b -> b') -> a -> a') -> SetterFamily a a' b b'
- type LensFamily a a' b b' = forall f. Functor f => RefFamily f a a' b b'
- type Lens a b = LensFamily a a b b
- type SetterFamily a a' b b' = RefFamily Setting a a' b b'
- type Setter a b = SetterFamily a a b b
Documentation
:: (a -> b) | getter |
-> (a -> b' -> a') | setter |
-> LensFamily 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:
getter (setter a b) === b
setter a (getter a) === a
setter (setter a b1) b2) === setter a b2
:: (a -> b) | yin |
-> (b' -> a') | yang |
-> LensFamily a a' b b' |
Build a lens from isomorphism families.
Caution: In order for the generated lens family to be well-defined, you must ensure that the two isomorphism laws hold:
yin . yang === id
yang . yin === id
:: ((b -> b') -> a -> a') | sec (semantic editor combinator) |
-> SetterFamily a a' b b' |
setting
promotes a "semantic editor combinator" to a modify-only lens.
To demote a lens to a semantic edit combinator, use the section (l %~)
or sec l
.
>>>
setting map . fstL %~ length $ [("The",0),("quick",1),("brown",1),("fox",2)]
[(3,0),(5,1),(5,1),(3,2)]
Caution: In order for the generated setter family to be well-defined, you must ensure that the two functors laws hold:
sec id === id
sec f . sec g === sec (f . g)
Types
type LensFamily a a' b b' = forall f. Functor f => RefFamily f a a' b b'Source
type Lens a b = LensFamily a a b bSource
type SetterFamily a a' b b' = RefFamily Setting a a' b b'
type Setter a b = SetterFamily a a b b