| Portability | Rank2Types |
|---|---|
| Stability | provisional |
| Maintainer | Edward Kmett <ekmett@gmail.com> |
| Safe Haskell | None |
Control.Lens.Traversal
Contents
Description
A is a generalization of Traversal s t a btraverse from
Traversable. It allows you to traverse over a structure and change out
its contents with monadic or applicative side-effects. Starting from
traverse:: (Traversablet,Applicativef) => (a -> f b) -> t a -> f (t b)
we monomorphize the contents and result to obtain
typeTraversals t a b = forall f.Applicativef => (a -> f b) -> s -> f t
While a Traversal isn't quite a Fold, it _can_ be used for Getting
like a Fold, because given a Monoid m, we have an Applicative
for (. Everything you know how to do with a Const m)Traversable
container, you can with with a Traversal, and here we provide
combinators that generalize the usual Traversable operations.
- type Traversal s t a b = forall f. Applicative f => (a -> f b) -> s -> f t
- traverseOf :: LensLike f s t a b -> (a -> f b) -> s -> f t
- forOf :: LensLike f s t a b -> s -> (a -> f b) -> f t
- sequenceAOf :: LensLike f s t (f b) b -> s -> f t
- mapMOf :: LensLike (WrappedMonad m) s t a b -> (a -> m b) -> s -> m t
- forMOf :: LensLike (WrappedMonad m) s t a b -> s -> (a -> m b) -> m t
- sequenceOf :: LensLike (WrappedMonad m) s t (m b) b -> s -> m t
- transposeOf :: LensLike ZipList s t [a] a -> s -> [t]
- mapAccumLOf :: LensLike (State acc) s t a b -> (acc -> a -> (acc, b)) -> acc -> s -> (acc, t)
- mapAccumROf :: LensLike (Backwards (State acc)) s t a b -> (acc -> a -> (acc, b)) -> acc -> s -> (acc, t)
- scanr1Of :: LensLike (Backwards (State (Maybe a))) s t a a -> (a -> a -> a) -> s -> t
- scanl1Of :: LensLike (State (Maybe a)) s t a a -> (a -> a -> a) -> s -> t
- partsOf :: Functor f => LensLike (BazaarT a a f) s t a a -> LensLike f s t [a] [a]
- partsOf' :: LensLike (Bazaar a a) s t a a -> Lens s t [a] [a]
- unsafePartsOf :: Functor f => LensLike (BazaarT a b f) s t a b -> LensLike f s t [a] [b]
- unsafePartsOf' :: LensLike (Bazaar a b) s t a b -> Lens s t [a] [b]
- holesOf :: LensLike (Bazaar a a) s t a a -> s -> [Context a a t]
- singular :: Functor f => LensLike (BazaarT a a f) s t a a -> LensLike f s t a a
- unsafeSingular :: Functor f => LensLike (BazaarT a b f) s t a b -> LensLike f s t a b
- class (Functor t, Foldable t) => Traversable t where
- traverse :: Applicative f => (a -> f b) -> t a -> f (t b)
- both :: Traversal (a, a) (b, b) a b
- beside :: Applicative f => LensLike f s t a b -> LensLike f s' t' a b -> LensLike f (s, s') (t, t') a b
- taking :: Applicative f => Int -> SimpleLensLike (BazaarT a a f) s a -> SimpleLensLike f s a
- dropping :: Applicative f => Int -> SimpleLensLike (Indexing f) s a -> SimpleLensLike f s a
- loci :: Traversal (Bazaar a c s) (Bazaar b c s) a b
- cloneTraversal :: Applicative f => ((a -> Bazaar a b b) -> s -> Bazaar a b t) -> (a -> f b) -> s -> f t
- data ReifiedTraversal s t a b = ReifyTraversal {
- reflectTraversal :: Traversal s t a b
- type SimpleTraversal s a = Traversal s s a a
- type SimpleReifiedTraversal s a = ReifiedTraversal s s a a
- newtype Bazaar a b t = Bazaar {
- runBazaar :: forall f. Applicative f => (a -> f b) -> f t
Lenses
type Traversal s t a b = forall f. Applicative f => (a -> f b) -> s -> f tSource
A Traversal can be used directly as a Setter or a Fold (but not as a Lens) and provides
the ability to both read and update multiple fields, subject to some relatively weak Traversal laws.
These have also been known as multilenses, but they have the signature and spirit of
traverse::Traversablef =>Traversal(f a) (f b) a b
and the more evocative name suggests their application.
Most of the time the Traversal you will want to use is just traverse, but you can also pass any
Lens or Iso as a Traversal, and composition of a Traversal (or Lens or Iso) with a Traversal (or Lens or Iso)
using (.) forms a valid Traversal.
The laws for a Traversal t follow from the laws for Traversable as stated in "The Essence of the Iterator Pattern".
tpure≡purefmap(t f).t g ≡getCompose.t (Compose.fmapf.g)
One consequence of this requirement is that a Traversal needs to leave the same number of elements as a
candidate for subsequent Traversal that it started with. Another testament to the strength of these laws
is that the caveat expressed in section 5.5 of the "Essence of the Iterator Pattern" about exotic
Traversable instances that traverse the same entry multiple times was actually already ruled out by the
second law in that same paper!
Traversing and Lensing
traverseOf :: LensLike f s t a b -> (a -> f b) -> s -> f tSource
Map each element of a structure targeted by a Lens or Traversal, evaluate these actions from left to right, and collect the results.
This function is only provided for consistency, id is strictly more general.
traverseOf≡id
This yields the obvious law:
traverse≡traverseOftraverse
traverseOf::Isos t a b -> (a -> f b) -> s -> f ttraverseOf::Lenss t a b -> (a -> f b) -> s -> f ttraverseOf::Traversals t a b -> (a -> f b) -> s -> f t
forOf :: LensLike f s t a b -> s -> (a -> f b) -> f tSource
A version of traverseOf with the arguments flipped, such that:
forOfl ≡flip(traverseOfl)
for≡forOftraverse
This function is only provided for consistency, flip is strictly more general.
forOf≡flip
forOf::Isos t a b -> s -> (a -> f b) -> f tforOf::Lenss t a b -> s -> (a -> f b) -> f tforOf::Traversals t a b -> s -> (a -> f b) -> f t
sequenceAOf :: LensLike f s t (f b) b -> s -> f tSource
Evaluate each action in the structure from left to right, and collect the results.
sequenceA≡sequenceAOftraverse≡traverseidsequenceAOfl ≡traverseOfl id ≡ l id
sequenceAOf::Isos t (f b) b -> s -> f tsequenceAOf::Lenss t (f b) b -> s -> f tsequenceAOf::Applicativef =>Traversals t (f b) b -> s -> f t
mapMOf :: LensLike (WrappedMonad m) s t a b -> (a -> m b) -> s -> m tSource
Map each element of a structure targeted by a lens to a monadic action, evaluate these actions from left to right, and collect the results.
mapM≡mapMOftraverse
mapMOf::Isos t a b -> (a -> m b) -> s -> m tmapMOf::Lenss t a b -> (a -> m b) -> s -> m tmapMOf::Monadm =>Traversals t a b -> (a -> m b) -> s -> m t
forMOf :: LensLike (WrappedMonad m) s t a b -> s -> (a -> m b) -> m tSource
sequenceOf :: LensLike (WrappedMonad m) s t (m b) b -> s -> m tSource
Sequence the (monadic) effects targeted by a lens in a container from left to right.
sequence≡sequenceOftraversesequenceOfl ≡mapMOfl idsequenceOfl ≡unwrapMonad. lWrapMonad
sequenceOf::Isos t (m b) b -> s -> m tsequenceOf::Lenss t (m b) b -> s -> m tsequenceOf::Monadm =>Traversals t (m b) b -> s -> m t
transposeOf :: LensLike ZipList s t [a] a -> s -> [t]Source
This generalizes transpose to an arbitrary Traversal.
Note: transpose handles ragged inputs more intelligently, but for non-ragged inputs:
transpose≡transposeOftraverse
>>>transposeOf traverse [[1,2,3],[4,5,6]][[1,4],[2,5],[3,6]]
Since every Lens is a Traversal, we can use this as a form of
monadic strength as well:
transposeOf_2:: (b, [a]) -> [(b, a)]
mapAccumLOf :: LensLike (State acc) s t a b -> (acc -> a -> (acc, b)) -> acc -> s -> (acc, t)Source
This generalizes mapAccumL to an arbitrary Traversal.
mapAccumL≡mapAccumLOftraverse
mapAccumLOf accumulates state from left to right.
mapAccumLOf::Isos t a b -> (acc -> a -> (acc, b)) -> acc -> s -> (acc, t)mapAccumLOf::Lenss t a b -> (acc -> a -> (acc, b)) -> acc -> s -> (acc, t)mapAccumLOf::Traversals t a b -> (acc -> a -> (acc, b)) -> acc -> s -> (acc, t)
mapAccumROf :: LensLike (Backwards (State acc)) s t a b -> (acc -> a -> (acc, b)) -> acc -> s -> (acc, t)Source
This generalizes mapAccumR to an arbitrary Traversal.
mapAccumR≡mapAccumROftraverse
mapAccumROf accumulates state from right to left.
mapAccumROf::Isos t a b -> (acc -> a -> (acc, b)) -> acc -> s -> (acc, t)mapAccumROf::Lenss t a b -> (acc -> a -> (acc, b)) -> acc -> s -> (acc, t)mapAccumROf::Traversals t a b -> (acc -> a -> (acc, b)) -> acc -> s -> (acc, t)
Parts and Holes
partsOf :: Functor f => LensLike (BazaarT a a f) s t a a -> LensLike f s t [a] [a]Source
partsOf turns a Traversal into a Lens that resembles an early version of the uniplate (or biplate) type.
Note: You should really try to maintain the invariant of the number of children in the list.
Any extras will be lost. If you do not supply enough, then the remainder will come from the original structure.
So technically, this is only a lens if you do not change the number of results it returns.
When applied to a Fold the result is merely a Getter.
partsOf::SimpleIsos a ->SimpleLenss [a]partsOf::SimpleLenss a ->SimpleLenss [a]partsOf::SimpleTraversals a ->SimpleLenss [a]partsOf::Folds a ->Getters [a]partsOf::Getters a ->Getters [a]
unsafePartsOf :: Functor f => LensLike (BazaarT a b f) s t a b -> LensLike f s t [a] [b]Source
unsafePartsOf turns a Traversal into a uniplate (or biplate) family.
If you do not need the types of s and t to be different, it is recommended that
you use partsOf
It is generally safer to traverse with the Bazaar rather than use this
combinator. However, it is sometimes convenient.
This is unsafe because if you don't supply at least as many b's as you were
given a's, then the reconstruction of t will result in an error!
When applied to a Fold the result is merely a Getter (and becomes safe).
unsafePartsOf::Isos t a b ->Lenss t [a] [b]unsafePartsOf::Lenss t a b ->Lenss t [a] [b]unsafePartsOf::Traversals t a b ->Lenss t [a] [b]unsafePartsOf::Folds a ->Getters [a]unsafePartsOf::Getters a ->Getters [a]
unsafePartsOf' :: LensLike (Bazaar a b) s t a b -> Lens s t [a] [b]Source
holesOf :: LensLike (Bazaar a a) s t a a -> s -> [Context a a t]Source
The one-level version of contextsOf. This extracts a list of the immediate children according to a given Traversal as editable contexts.
Given a context you can use pos to see the values, peek at what the structure would be like with an edited result, or simply extract the original structure.
propChildren l x =childrenOfl x==mappos(holesOfl x) propId l x =all(==x) [extract w | w <-holesOfl x]
holesOf::SimpleIsos a -> s -> [Contexta a s]holesOf::SimpleLenss a -> s -> [Contexta a s]holesOf::SimpleTraversals a -> s -> [Contexta a s]
singular :: Functor f => LensLike (BazaarT a a f) s t a a -> LensLike f s t a aSource
This converts a Traversal that you know will target one or more elements to a Lens. It can
also be used to transform a non-empty Fold into a Getter or a non-empty MonadicFold into an
Action.
The resulting Lens, Getter, or Action will be partial if the supplied traversal returns
no results.
singular::Traversals t a a ->Lenss t a asingular::Folds a ->Getters asingular::MonadicFoldm s a ->Actionm s a
unsafeSingular :: Functor f => LensLike (BazaarT a b f) s t a b -> LensLike f s t a bSource
This converts a Traversal that you know will target only one element to a Lens. It can also be
used to transform a Fold into a Getter or a MonadicFold into an Action.
The resulting Lens, Getter, or Action will be partial if the Traversal targets nothing
or more than one element.
unsafeSingular::Traversals t a b ->Lenss t a bunsafeSingular::Folds a ->Getters aunsafeSingular::MonadicFoldm s a ->Actionm s a
Common Traversals
class (Functor t, Foldable t) => Traversable t where
Functors representing data structures that can be traversed from left to right.
Minimal complete definition: traverse or sequenceA.
Instances are similar to Functor, e.g. given a data type
data Tree a = Empty | Leaf a | Node (Tree a) a (Tree a)
a suitable instance would be
instance Traversable Tree where
traverse f Empty = pure Empty
traverse f (Leaf x) = Leaf <$> f x
traverse f (Node l k r) = Node <$> traverse f l <*> f k <*> traverse f r
This is suitable even for abstract types, as the laws for <*>
imply a form of associativity.
The superclass instances should satisfy the following:
- In the
Functorinstance,fmapshould be equivalent to traversal with the identity applicative functor (fmapDefault). - In the
Foldableinstance,foldMapshould be equivalent to traversal with a constant applicative functor (foldMapDefault).
Methods
traverse :: Applicative f => (a -> f b) -> t a -> f (t b)
Map each element of a structure to an action, evaluate these actions from left to right, and collect the results.
Instances
both :: Traversal (a, a) (b, b) a bSource
Traverse both parts of a tuple with matching types.
>>>both *~ 10 $ (1,2)(10,20)
>>>over both length ("hello","world")(5,5)
>>>("hello","world")^.both"helloworld"
beside :: Applicative f => LensLike f s t a b -> LensLike f s' t' a b -> LensLike f (s, s') (t, t') a bSource
taking :: Applicative f => Int -> SimpleLensLike (BazaarT a a f) s a -> SimpleLensLike f s aSource
dropping :: Applicative f => Int -> SimpleLensLike (Indexing f) s a -> SimpleLensLike f s aSource
Cloning Traversals
cloneTraversal :: Applicative f => ((a -> Bazaar a b b) -> s -> Bazaar a b t) -> (a -> f b) -> s -> f tSource
A Traversal is completely characterized by its behavior on a Bazaar.
Cloning a Traversal is one way to make sure you aren't given
something weaker, such as a Fold and can be
used as a way to pass around traversals that have to be monomorphic in f.
Note: This only accepts a proper Traversal (or Lens). To clone a Lens
as such, use cloneLens
Note: It is usually better to ReifyTraversal and use reflectTraversal
than to cloneTraversal. The former can execute at full speed, while the
latter needs to round trip through the Bazaar.
>>>let foo l a = (view (cloneTraversal l) a, set (cloneTraversal l) 10 a)>>>foo both ("hello","world")("helloworld",(10,10))
cloneTraversal::LensLike(Bazaara b) s t a b ->Traversals t a b
data ReifiedTraversal s t a b Source
A form of Traversal that can be stored monomorphically in a container.
Constructors
| ReifyTraversal | |
Fields
| |
Simple
type SimpleTraversal s a = Traversal s s a aSource
type SimpleReifiedTraversal s a = ReifiedTraversal s s a aSource
type SimpleReifiedTraversal =SimpleReifiedTraversal
Exposed Implementation Details
This is used to characterize a Traversal.
a.k.a. indexed Cartesian store comonad, indexed Kleene store comonad, or an indexed FunList.
http://twanvl.nl/blog/haskell/non-regular1
is isomorphic to Bazaar a b tdata Bazaar a b t = Buy t | Trade (Bazaar a b (b -> t)) a,
and to exists s. (s, .
Traversal s t a b)
A Bazaar is like a Traversal that has already been applied to some structure.
Where a holds an Context a b ta and a function from b to
t, a holds N Bazaar a b tas and a function from N
bs to t.
Mnemonically, a Bazaar holds many stores and you can easily add more.
This is a final encoding of Bazaar.
Constructors
| Bazaar | |
Fields
| |