Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
Caution: Improper use of this module can lead to unexpected behaviour if the preconditions of the functions are not met.
Synopsis
- adapter :: (Functor f, Functor g) => (s -> a) -> (b -> t) -> AdapterLike f g s t a b
- lens :: Functor f => (s -> a) -> (s -> b -> t) -> LensLike f s t a b
- prism :: (Applicative f, Traversable g) => (s -> Either t a) -> (b -> t) -> AdapterLike f g s t a b
- grate :: Functor g => (((s -> a) -> b) -> t) -> GrateLike g s t a b
- setting :: Identical f => ((a -> b) -> s -> t) -> LensLike f s t a b
- resetting :: Identical g => ((a -> b) -> s -> t) -> GrateLike g s t a b
- type AdapterLike f g s t a b = (g a -> f b) -> g s -> f t
- type AdapterLike' f g s a = (g a -> f a) -> g s -> f s
- type LensLike f s t a b = (a -> f b) -> s -> f t
- type LensLike' f s a = (a -> f a) -> s -> f s
- type GrateLike g s t a b = (g a -> b) -> g s -> t
- type GrateLike' g s a = (g a -> a) -> g s -> s
- class (Traversable f, Applicative f) => Identical f
Adapters
An adapter represents a isomorphism between two types or a parametric isomorphism between two families of types.
For example we can build an adapter between the type families
and Either
a a(
as follows:Bool
, a)
timesTwo :: (Functor f, Functor g) => AdapterLike f g (Either a a) (Either b b) (Bool, a) (Bool b) timesTwo f x = fmap yang . f . fmap yin where yin (True, a) = Left a yin (False, a) = Right a yang (Left a) = (True, a) yang (Right a) = (False, a)
Note: It is possible to adapters without even depending on lens-family-core
by expanding away the type synonym.
timesTwo :: (Functor f, Functor g) => (g (Either a a) -> f (Either b b)) -> g (Bool, a) -> f (Bool, b)
The function adapter
can also be used to construct adapters from a pair of mutually inverse functions.
Lenses
A lens focuses on a field of record type. Lenses can be used to get and/or set the focused field. 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, _myInt :: Int } -- The use of type variables a and b allow for polymorphic updates. myA :: Functor f => LensLike f (MyRecord a) (MyRecord b) a b myA f (MyRecord a i) = (\b -> MyRecord b i) <$> f a -- The field _myInt is monomorphic, so we can use a 'LensLike'' type. -- However, the structure of the function is exactly the same as for LensLike. myInt :: Functor f => LensLike' f (MyRecord a) Int myInt f (MyRecord a i) = (\i' -> MyRecord a i') <$> f i
See the lens-family-th
package to generate this sort of code using Template Haskell.
Note: It is possible to build lenses without even depending on lens-family-core
by expanding away the type synonym.
myA :: Functor f => (a -> f b) -> (MyRecord a) -> f (MyRecord b)
You can build lenses for more than just fields of records.
Any value l :: Functor f => LensLike f s t a 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 function lens
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, _myC :: Bool } -- myInts is a traversal over both fields of MyRecord. myInts :: Applicative f => LensLike' f MyRecord Int myInts f (MyRecord a b c) = MyRecord <$> f a <*> f b <*> pure c
If the record and the referenced fields are parametric, you can can build polymrphic traversals.
Consider the following example of a record with two Maybe
fields.
data MyRecord a = MyRecord { _myA0 :: Maybe a, _myA1 :: Maybe a, myC :: Bool } -- myMaybes is a traversal over both fields of MyRecord. myMaybes :: Applicative f => LensLike f (MyRecord a) (MyRecord b) (Maybe a) (Maybe b) myMaybes f (MyRecord a0 a1 c) = MyRecord <$> f a0 <*> f a1 <*> pure c
Note: It is possible to build traversals without even depending on lens-family-core
by expanding away the type synonym.
myMaybes :: Applicative f => (Maybe a -> f (Maybe b)) -> MyRecord a -> f (MyRecord b) myMaybes f (MyRecord a0 a1 c) = MyRecord <$> f a0 <*> f a1 <*> pure c
Unfortunately, there are no helper functions for making traversals. In most cases, you must make them by hand.
Any value t :: Applicative f => LensLike f s t a 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.
Prisms
A prism focuses on a single variant of a type.
They can be used to matching
/ review
the focused variant.
Consider the following example.
data MySum a = MyA a | MyB Int -- myA is a prism for the MyA variant of MySum myA :: (Applicative f, Traversable g) => AdapterLike f g (MySum a) (MySum b) a b myA f = either pure (fmap MyA . f) . traverse h where h (MyA a) = Right a h (MyB n) = Left (MyB n)
This prism can be used with matching
via under
:
matching
(under
myA) :: MySum a -> Either (MySum b) a
This prism can be used with review
via over
:
review
(over
myA) :: a -> MySum a
Note: It is possible to build prisms without even depending on lens-family-core
by expanding away the type synonym.
myA :: (Appicative f, Traversable g) => (g a -> f b) -> g (MySum a) -> f (MySum b)
You can build prism for more than just constructors of sum types.
Any value p :: (Applicative f, Traversable g) => AdapterLike f g s t a b
is well-defined when it satisfies the prism laws:
matching (under p) (review (over p) b) === Right b
(id ||| review (over p)) (matching (under p) s) === s
left (match (under p)) (matching (under p) s) === left Left (matching (under p) s)
The function prism
can also be used to construct prisms.
The resulting prisms will be well-defined so long as their preconditions are satisfied.
Grates
A grate focuses on the contents of a representable functor.
In other words, a grate focuses on the codomain of a function type or something isomorphic to a function type.
They are used to lift operations on this codomain to operations on the larger structure via zipping.
Consider the following example of a stream of Int
s.
data IntStream = IntStream { hd :: Int, tl :: IntStream } -- myInts is a grate over the Ints of IntStream. myInts :: Functor g => GrateLike' g IntStream Int myInts f s = IntStream (f (hd <$> s)) (myInts f (tl <$> s))
If the contents are parametric, you can can build polymorphic grates. Consider the following example of a generic stream.
data Stream a = Stream { hd :: a, tl :: Stream a } -- myStream is a grate over the contents of a Stream. myStream :: Functor g => GrateLike g (Stream a) (Stream b) a b myStream f s = Stream (f (hd <$> s)) (myStream f (tl <$> s))
Note: It is possible to build grates without even depending on lens-family-core
by expanding away the type synonym.
myStream :: Functor g => (g (Stream a) -> Stream b) -> g a -> b
Any value t :: Functor g => GrateLike g s t a b
is a well-defined grate when it satisfies the two van Laarhoven traversal laws:
t runIdentity === runIdentity
t (f . fmap g . runCompose) === (t f) . fmap (t g) . runCompose
The function grate
can also be used to construct grates from graters.
The resulting grates will be well-defined so long as the preconditions are satisfied.
Grids
A grid is both a traversal and a grate.
When you have a type that is isomorphic to a fixed and finite number of copies of another type, a grid can be used to zip or traverse them.
Consider the following example of a record with exactly two Int
fields.
data MyRecord = MyRecord { _myA :: Int, _myB :: Int } -- myInts is a grid over both fields of MyRecord. myInts :: (Applicative f, Functor g) => AdapterLike' f g MyRecord Int myInts f r = MyRecord <$> f (_myA <$> r) <*> f (_myB <$> r)
If the record and the referenced fields are parametric, you can can build polymorphic grids.
Consider the following example of a record with exactly two Maybe
fields.
data MyRecord a = MyRecord { _myA0 :: Maybe a, _myA1 :: Maybe a } -- myMaybes is a traversal over both fields of MyRecord. myMaybes :: (Applicative f, Functor g) => AdapterLike f g (MyRecord a) (MyRecord b) (Maybe a) (Maybe b) myMaybes f r = MyRecord <$> f (_myA0 <$> r) <*> f (_myA1 <$> r)
A grid is converted into a grate by using the over
function, and it is converted to a traversal by using the under
function.
Note: It is possible to build grids without even depending on lens-family-core
by expanding away the type synonym.
myMaybes :: (Applicative f, Functor g) => (g (Maybe a) -> f (Maybe b)) -> g (MyRecord a) -> f (MyRecord b)
Unfortunately, there are no helper functions for making grids. In most cases, you must make them by hand.
Documentation
:: (Functor f, Functor g) | |
=> (s -> a) | yin |
-> (b -> t) | yang |
-> AdapterLike f g s t a b |
adapter :: (s -> a) -> (b -> t) -> Adapter s t a b
Build an adapter from an isomorphism family.
Caution: In order for the generated adapter family to be well-defined, you must ensure that the two isomorphism laws hold:
yin . yang === id
yang . yin === id
lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b
Build a lens from a getter
and setter
family.
Caution: In order for the generated lens family to be well-defined, you must ensure that the three lens laws hold:
getter (setter s a) === a
setter s (getter s) === s
setter (setter s a1) a2 === setter s a2
:: (Applicative f, Traversable g) | |
=> (s -> Either t a) | matcher |
-> (b -> t) | reviewer |
-> AdapterLike f g s t a b |
prism :: (s -> Either t a) -> (b -> t) -> Prism s t a b
Build a prism from a matcher
and reviewer
family.
Caution: In order for the generated prism family to be well-defined, you must ensure that the three prism laws hold:
matcher (reviewer b) === Right b
(id ||| reviewer) (matcher s) === s
left matcher (matcher s) === left Left (matcher s)
grate :: (((s -> a) -> b) -> t) -> Grate s t a b
Build a grate from a grater
family.
Caution: In order for the generated grate family to be well-defined, you must ensure that the two grater laws hold:
grater ($ s) === s
grater (k -> h (k . grater)) === grater (k -> h ($ k))
Note: The grater laws are that of an algebra for the parameterised continuation monad, PCont
.
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.
>>>
[("The",0),("quick",1),("brown",1),("fox",2)] & setting map . fstL %~ length
[(3,0),(5,1),(5,1),(3,2)]
Caution: In order for the generated family to be well-defined, you must ensure that the two functors laws hold:
sec id === id
sec f . sec g === sec (f . g)
resetting
promotes a "semantic editor combinator" to a form of grate that can only lift unary functions.
To demote a grate to a semantic edit combinator, use under l
from Lens.Family.
Caution: In order for the generated 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 AdapterLike f g s t a b = (g a -> f b) -> g s -> f t Source #
type AdapterLike' f g s a = (g a -> f a) -> g s -> f s Source #
type GrateLike' g s a = (g a -> a) -> g s -> s Source #
class (Traversable f, Applicative f) => Identical f Source #
extract