Safe Haskell | Safe |
---|---|
Language | Haskell98 |
Caution: Improper use of this module can lead to unexpected behaviour if the preconditions of the functions are not met.
Synopsis
- lens :: Functor f => (a -> b) -> (a -> b' -> a') -> LensLike f a a' b b'
- iso :: Functor f => (a -> b) -> (b' -> a') -> LensLike f a a' b b'
- setting :: Identical f => ((b -> b') -> a -> a') -> LensLike f a a' b b'
- type LensLike f a a' b b' = (b -> f b') -> a -> f a'
- type LensLike' f a b = (b -> f b) -> a -> f a
- class Applicative f => Identical f
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 :: Functor f => LensLike f (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 'LensLike'' type. -- However, the structure of the function is exactly the same as for LensLike. myB :: Functor f => LensLike' f (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 LensLike
and LensLike'
, 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-core
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 l :: Functor f => LensLike f a a' b b'
is well-defined when it satisfies the two van Laarhoven lens laws:
l Identity === Identity
l (Compose . fmap f . g) === Compose . fmap (l f) . (l g)
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.
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 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 :: Applicative f => LensLike' f 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 :: Applicative f => LensLike f (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 :: Applicative f => LensLike f 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)
traverse
is the canonical traversal for various containers.
Documentation
lens :: (a -> b) -> (a -> b' -> a') -> Lens 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
iso :: (a -> b) -> (b' -> a') -> Lens 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
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 over l
from Lens.Family.
>>>
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)