lens-3.0: Lenses, Folds and Traversals

PortabilityRank2Types
Stabilityprovisional
MaintainerEdward Kmett <ekmett@gmail.com>
Safe HaskellNone

Control.Lens.Plated

Contents

Description

The name "plate" stems originally from "boilerplate", which was the term used by the "Scrap Your Boilerplate" papers, and later inherited by Neil Mitchell's "Uniplate".

http://community.haskell.org/~ndm/uniplate/

The combinators in here are designed to be compatible with and subsume the uniplate API with the notion of a Traversal replacing a uniplate or biplate.

By implementing these combinators in terms of plate instead of uniplate additional type safety is gained, as the user is no longer responsible for maintaining invariants such as the number of children he received.

Note: The Biplate is deliberately excluded from the API here, with the intention that you replace them with either explicit traversals, or by using the On variants of the combinators below with biplate from Data.Data.Lens. As a design, it forced the user into too many situations where they had to choose between correctness and ease of use, and it was brittle in the face of competing imports.

The sensible use of these combinators makes some simple assumptions. Notably, any of the On combinators are expecting a Traversal, Setter or Fold to play the role of the biplate combinator, and so when the types of the contents and the container match, they should be the id Traversal, Setter or Fold.

It is often beneficial to use the combinators in this module with the combinators from Data.Data.Lens or GHC.Generics.Lens to make it easier to automatically derive definitions for plate, or to derive custom traversals.

Synopsis

Uniplate

class Plated a whereSource

A Plated type is one where we know how to extract its immediate self-similar children.

Example 1:

 import Control.Applicative
 import Control.Lens
 import Control.Plated
 import Data.Data
 import Data.Data.Lens (uniplate)
 data Expr
   = Val Int
   | Neg Expr
   | Add Expr Expr
   deriving (Eq,Ord,Show,Read,Data,Typeable)
 instance Plated Expr where
   plate f (Neg e) = Neg <$> f e
   plate f (Add a b) = Add <$> f a <*> f b
   plate _ a = pure a

or

 instance Plated Expr where
   plate = uniplate

Example 2:

 import Control.Applicative
 import Control.Lens
 import Control.Plated
 import Data.Data
 import Data.Data.Lens (uniplate)
 data Tree a
   = Bin (Tree a) (Tree a)
   | Tip a
   deriving (Eq,Ord,Show,Read,Data,Typeable)
 instance Plated (Tree a) where
   plate f (Bin l r) = Bin <$> f l <*> f r
   plate _ t = pure t

or

 instance Data a => Plated (Tree a) where
   plate = uniplate

Note the big distinction between these two implementations.

The former will only treat children directly in this tree as descendents, the latter will treat trees contained in the values under the tips also as descendants!

When in doubt, pick a Traversal and just use the various ...Of combinators rather than pollute Plated with orphan instances!

If you want to find something unplated and non-recursive with biplate use the ...OnOf variant with ignored, though those usecases are much better served in most cases by using the existing lens combinators! e.g.

toListOf biplateuniverseOnOf biplate ignored.

This same ability to explicitly pass the Traversal in question is why there is no analogue to uniplate's Biplate.

Moreover, since we can allow custom traversals, we implement reasonable defaults for polymorphic data types, that only traverse into themselves, and not their polymorphic arguments.

Methods

plate :: Simple Traversal a aSource

Traversal of the immediate children of this structure.

The default definition finds no children.

Instances

Plated [a] 
Plated (Tree a) 

Uniplate Combinators

children :: Plated a => a -> [a]Source

Extract the immediate descendants of a Plated container.

childrentoListOf plate

childrenOn :: Getting [c] a b c d -> a -> [c]Source

Provided for compatibility with uniplate.

childrenOntoListOf
childrenOn :: Fold a c -> a -> [c]

rewrite :: Plated a => (a -> Maybe a) -> a -> aSource

Rewrite by applying a rule everywhere you can. Ensures that the rule cannot be applied anywhere in the result:

propRewrite r x = all (isNothing . r) (universe (rewrite r x))

Usually transform is more appropriate, but rewrite can give better compositionality. Given two single transformations f and g, you can construct a -> f a mplus g a which performs both rewrites until a fixed point.

rewriteOf :: SimpleSetting a a -> (a -> Maybe a) -> a -> aSource

Rewrite by applying a rule everywhere you can. Ensures that the rule cannot be applied anywhere in the result:

propRewriteOf l r x = all (isNothing . r) (universeOf l (rewriteOf l r x))

Usually transformOf is more appropriate, but rewriteOf can give better compositionality. Given two single transformations f and g, you can construct a -> f a mplus g a which performs both rewrites until a fixed point.

 rewriteOf :: Simple Iso a a       -> (a -> Maybe a) -> a -> a
 rewriteOf :: Simple Lens a a      -> (a -> Maybe a) -> a -> a
 rewriteOf :: Simple Traversal a a -> (a -> Maybe a) -> a -> a
 rewriteOf :: Simple Setter a a    -> (a -> Maybe a) -> a -> a

rewriteOn :: Plated c => Setting a b c c -> (c -> Maybe c) -> a -> bSource

Rewrite recursively over part of a larger structure.

 rewriteOn :: Plated c => Simple Iso a b       -> (b -> Maybe b) -> a -> a
 rewriteOn :: Plated c => Simple Lens a b      -> (b -> Maybe b) -> a -> a
 rewriteOn :: Plated c => Simple Traversal a b -> (b -> Maybe b) -> a -> a
 rewriteOn :: Plated c => Simple Setting a b   -> (b -> Maybe b) -> a -> a

rewriteOnOf :: Setting a b c c -> SimpleSetting c c -> (c -> Maybe c) -> a -> bSource

Rewrite recursively over part of a larger structure using a specified setter.

 rewriteOnOf :: Plated b => Simple Iso a b       -> Simple Iso b b       -> (b -> Maybe b) -> a -> a
 rewriteOnOf :: Plated b => Simple Lens a b      -> Simple Lens b b      -> (b -> Maybe b) -> a -> a
 rewriteOnOf :: Plated b => Simple Traversal a b -> Simple Traversal b b -> (b -> Maybe b) -> a -> a
 rewriteOnOf :: Plated b => Simple Setter a b    -> Simple Setter b b    -> (b -> Maybe b) -> a -> a

rewriteM :: (Monad m, Plated a) => (a -> m (Maybe a)) -> a -> m aSource

Rewrite by applying a monadic rule everywhere you can. Ensures that the rule cannot be applied anywhere in the result.

rewriteMOf :: Monad m => SimpleLensLike (WrappedMonad m) a a -> (a -> m (Maybe a)) -> a -> m aSource

Rewrite by applying a monadic rule everywhere you recursing with a user-specified Traversal. Ensures that the rule cannot be applied anywhere in the result.

rewriteMOn :: (Monad m, Plated c) => LensLike (WrappedMonad m) a b c c -> (c -> m (Maybe c)) -> a -> m bSource

Rewrite by applying a monadic rule everywhere inside of a structure located by a user-specified Traversal. Ensures that the rule cannot be applied anywhere in the result.

rewriteMOnOf :: Monad m => LensLike (WrappedMonad m) a b c c -> SimpleLensLike (WrappedMonad m) c c -> (c -> m (Maybe c)) -> a -> m bSource

Rewrite by applying a monadic rule everywhere inside of a structure located by a user-specified Traversal, using a user-specified Traversal for recursion. Ensures that the rule cannot be applied anywhere in the result.

universe :: Plated a => a -> [a]Source

Retrieve all of the transitive descendants of a Plated container, including itself.

universeOf :: Getting [a] a b a b -> a -> [a]Source

Given a fold that knows how to locate immediate children, retrieve all of the transitive descendants of a node, including itself.

universeOf :: Fold a a -> a -> [a]

universeOn :: Plated c => Getting [c] a b c c -> a -> [c]Source

Given a Fold that knows how to find Plated parts of a container retrieve them and all of their descendants, recursively.

universeOnOf :: Getting [c] a b c d -> Getting [c] c d c d -> a -> [c]Source

Given a Fold that knows how to locate immediate children, retrieve all of the transitive descendants of a node, including itself that lie in a region indicated by another Fold.

toListOf l ≡ universeOnOf l ignored

transform :: Plated a => (a -> a) -> a -> aSource

Transform every element in the tree, in a bottom-up manner.

For example, replacing negative literals with literals:

 negLits = transform $ x -> case x of
   Neg (Lit i) -> Lit (negate i)
   _           -> x

transformOf :: SimpleSetting a a -> (a -> a) -> a -> aSource

Transform every element by recursively applying a given Setter in a bottom-up manner.

 transformOf :: Simple Traversal a a -> (a -> a) -> a -> a
 transformOf :: Simple Setter a a    -> (a -> a) -> a -> a

transformOn :: Plated c => Setting a b c c -> (c -> c) -> a -> bSource

Transform every element in the tree in a bottom-up manner over a region indicated by a Setter.

 transformOn :: Plated b => Simple Traversal a b -> (b -> b) -> a -> a
 transformOn :: Plated b => Simple Setter a b    -> (b -> b) -> a -> a

transformOnOf :: Setting a b c c -> SimpleSetting c c -> (c -> c) -> a -> bSource

Transform every element in a region indicated by a Setter by recursively applying another Setter in a bottom-up manner.

 transformOnOf :: Setter a b -> Simple Traversal b b -> (b -> b) -> a -> a
 transformOnOf :: Setter a b -> Simple Setter b b    -> (b -> b) -> a -> a

transformM :: (Monad m, Plated a) => (a -> m a) -> a -> m aSource

Transform every element in the tree, in a bottom-up manner, monadically.

transformMOf :: Monad m => SimpleLensLike (WrappedMonad m) a a -> (a -> m a) -> a -> m aSource

Transform every element in a tree using a user supplied Traversal in a bottom-up manner with a monadic effect.

transformMOf :: Monad m => 'Simple Traversal a a -> (a -> m a) -> a -> m a

transformMOn :: (Monad m, Plated c) => LensLike (WrappedMonad m) a b c c -> (c -> m c) -> a -> m bSource

Transform every element in the tree in a region indicated by a supplied Traversal, in a bottom-up manner, monadically.

transformMOn :: (Monad m, Plated c) => Simple Traversal a b -> (b -> m b) -> a -> m a

transformMOnOf :: Monad m => LensLike (WrappedMonad m) a b c c -> SimpleLensLike (WrappedMonad m) c c -> (c -> m c) -> a -> m bSource

Transform every element in a tree that lies in a region indicated by a supplied Traversal, walking with a user supplied Traversal in a bottom-up manner with a monadic effect.

transformMOnOf :: Monad m => Simple Traversal a b -> Simple Traversal b b -> (b -> m b) -> a -> m a

descend :: Plated a => (a -> a) -> a -> aSource

Recurse one level into a structure. (a.k.a composOp from Björn Bringert's compos)

descendover plate

descendOf :: Setting a b c d -> (c -> d) -> a -> bSource

Recurse one level into a structure using a user specified recursion scheme. This is over, but it is supplied here for consistency with the uniplate API.

descendOfover
 descendOf :: Simple Setter a b -> (b -> b) -> a -> a
 descendOf :: Simple Traversal a b -> (b -> b) -> a -> a

descendOn :: Plated c => Setting a b c c -> (c -> c) -> a -> bSource

Recurse one level into the parts of the structure delimited by a Setter.

descendOn b ≡ over (b . plate)
descendOn :: Plated c => Setter a b -> (b -> b) -> a -> a

descendOnOf :: Setting a b c d -> Setting c d e f -> (e -> f) -> a -> bSource

Recurse one level into the parts delimited by one Setter, using another.

descendOnOf b l ≡ over (b . l)
 descendOnOf :: Simple Setter a b    -> Simple Setter b b    -> (b -> b) -> a -> a
 descendOnOf :: Simple Traversal a b -> Simple Traversal b b -> (b -> b) -> a -> a

descendA :: (Applicative f, Plated a) => (a -> f a) -> a -> f aSource

Recurse one level into a structure with an Applicative effect, this is plate, but it is supplied for consistency with the uniplate API.

descendAplate

descendAOf :: Applicative f => LensLike f a b c d -> (c -> f d) -> a -> f bSource

Recurse one level into a structure using a user specified recursion scheme and Applicative effects. This is id, but it is supplied for consistency with the uniplate API.

descendAOfid
descendAOf :: Applicative m => Simple Traversal a b => (b -> m b) -> a -> m a

descendAOn :: (Applicative f, Plated c) => LensLike f a b c c -> (c -> f c) -> a -> f bSource

Recurse one level into the parts of the structure delimited by a Traversal with Applicative effects.

descendAOn b ≡ b . plate
descendAOn :: (Applicative f, Plated' c) => Simple Traversal a b -> (b -> f b) -> a -> f a

descendAOnOf :: Applicative g => LensLike g a b c d -> LensLike g c d e f -> (e -> g f) -> a -> g bSource

Recurse one level into the parts delimited by one Traversal, using another with Applicative effects.

descendAOnOf ≡ (.)
descendAOnOf :: Applicative f => Simple Traversal a b -> Simple Traversal b b -> (b -> f b) -> a -> f a

descendA_ :: (Applicative f, Plated a) => (a -> f b) -> a -> f ()Source

descendA_ ≡ traverseOf_' plate

descendAOf_ :: Applicative f => Getting (Traversed f) a b c d -> (c -> f e) -> a -> f ()Source

Recurse one level into a structure using a user specified recursion scheme and Applicative effects, without reconstructing the structure behind you.

This is just traverseOf_, but is provided for consistency.

descendAOf_traverseOf_
descendAOf_ :: Applicative f => Fold a b => (b -> f b) -> a -> f ()

descendAOn_ :: (Applicative f, Plated c) => Getting (Traversed f) a b c c -> (c -> f e) -> a -> f ()Source

Recurse one level into the parts of the structure delimited by a Traversal with monadic effects.

descendAOn_ b ≡ traverseOf_ (b . plate)
descendAOn_ :: (Applicative f, Plated b) => Simple Traversal a b -> (b -> f c) -> a -> f ()

descendAOnOf_ :: Applicative f => Getting (Traversed f) a b c d -> Getting (Traversed f) c d c d -> (c -> f e) -> a -> f ()Source

Recurse one level into the parts delimited by one Fold, using another with Applicative effects, without reconstructing the structure behind you.

descendAOnOf_ b l ≡ traverseOf_ (b . l)
descendAOnOf_ :: Applicative f => Fold a b -> Fold b b -> (b -> f c) -> a -> f ()

descendM :: (Monad m, Plated a) => (a -> m a) -> a -> m aSource

Recurse one level into a structure with a monadic effect. (a.k.a composOpM from Björn Bringert's compos)

descendMmapMOf plate

descendMOf :: Monad m => LensLike (WrappedMonad m) a b c d -> (c -> m d) -> a -> m bSource

Recurse one level into a structure using a user specified recursion scheme and monadic effects. This is id, but it is supplied for consistency with the uniplate API.

descendMOfmapMOf
descendMOf :: Monad m => Simple Traversal a b => (b -> m b) -> a -> m a

descendMOn :: (Monad m, Plated c) => LensLike (WrappedMonad m) a b c c -> (c -> m c) -> a -> m bSource

Recurse one level into the parts of the structure delimited by a Traversal with monadic effects.

descendMOn b ≡ mapMOf (b . plate)
descendMOn :: (Monad m, Plated c) => Simple Traversal a b -> (b -> m b) -> a -> m a

descendMOnOf :: Monad m => LensLike (WrappedMonad m) a b c c -> SimpleLensLike (WrappedMonad m) c c -> (c -> m c) -> a -> m bSource

Recurse one level into the parts delimited by one Traversal, using another with monadic effects.

descendMOnOf b l ≡ mapMOf (b . l)
descendMOnOf :: Monad m => Simple Traversal a b -> Simple Traversal b b -> (b -> m b) -> a -> m a

descendM_ :: (Monad m, Plated a) => (a -> m b) -> a -> m ()Source

Descend one level into a structure with monadic effects (a.k.a composOpM from Björn Bringert's compos)

descendM_ ≡ mapMOf_' plate

descendMOf_ :: Monad m => Getting (Sequenced m) a b c d -> (c -> m e) -> a -> m ()Source

Recurse one level into a structure using a user specified recursion scheme and monadic effects. This is just mapMOf_, but is provided for consistency.

descendMOf_mapMOf_
descendMOf_ :: Monad m => Fold a b => (b -> m b) -> a -> m ()

descendMOn_ :: (Monad m, Plated c) => Getting (Sequenced m) a b c c -> (c -> m e) -> a -> m ()Source

Recurse one level into the parts of the structure delimited by a Traversal with monadic effects.

descendMOn_ b ≡ mapMOf_ (b . plate)
descendMOn_ :: (Monad m, Plated b) => Simple Traversal a b -> (b -> m c) -> a -> m ()

descendMOnOf_ :: Monad m => Getting (Sequenced m) a b c d -> Getting (Sequenced m) c d c d -> (c -> m e) -> a -> m ()Source

Recurse one level into the parts delimited by one Traversal, using another with monadic effects.

descendMOnOf_ b l ≡ mapMOf_ (b . l)
descendMOnOf_ :: Monad m => Fold a b -> Fold b b -> (b -> m b) -> a -> m ()

contexts :: Plated a => a -> [Context a a a]Source

Return a list of all of the editable contexts for every location in the structure, recursively.

 propUniverse x = universe x == map pos (contexts x)
 propId x = all (== x) [extract w | w <- contexts x]
contextscontextsOf plate

contextsOf :: SimpleLensLike (Bazaar a a) a a -> a -> [Context a a a]Source

Return a list of all of the editable contexts for every location in the structure, recursively, using a user-specified Traversal to walk each layer.

 propUniverse l x = universeOf l x == map pos (contextsOf l x)
 propId l x = all (== x) [extract w | w <- contextsOf l x]
contextsOf :: Simple Traversal a a -> a -> [Context a a]

contextsOn :: Plated c => LensLike (Bazaar c c) a b c c -> a -> [Context c c b]Source

Return a list of all of the editable contexts for every location in the structure in an areas indicated by a user supplied Traversal, recursively using plate.

contextsOn b ≡ contextsOnOf b plate
contextsOn :: Plated b => Simple Traversal a b -> a -> [Context b b a]

contextsOnOf :: LensLike (Bazaar c c) a b c c -> SimpleLensLike (Bazaar c c) c c -> a -> [Context c c b]Source

Return a list of all of the editable contexts for every location in the structure in an areas indicated by a user supplied Traversal, recursively using another user-supplied Traversal to walk each layer.

contextsOnOf :: Simple Traversal a b -> Simple Traversal b b -> a -> [Context b b a]

holes :: Plated a => a -> [Context a a a]Source

The one-level version of context. This extracts a list of the immediate children 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 x = children l x == map pos (holes l x)
 propId x = all (== x) [extract w | w <- holes l x]
holes = holesOf plate

holesOf :: LensLike (Bazaar c c) a b c c -> a -> [Context c c b]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 = childrenOf l x == map pos (holesOf l x)
 propId l x = all (== x) [extract w | w <- holesOf l x]
 holesOf :: Simple Iso a b       -> a -> [Context b a]
 holesOf :: Simple Lens a b      -> a -> [Context b a]
 holesOf :: Simple Traversal a b -> a -> [Context b a]

holesOn :: LensLike (Bazaar c c) a b c c -> a -> [Context c c b]Source

An alias for holesOf, provided for consistency with the other combinators.

holesOnholesOf
 holesOn :: Simple Iso a b       -> a -> [Context b b a]
 holesOn :: Simple Lens a b      -> a -> [Context b b a]
 holesOn :: Simple Traversal a b -> a -> [Context b b a]

holesOnOf :: LensLike (Bazaar e e) a b c d -> LensLike (Bazaar e e) c d e e -> a -> [Context e e b]Source

Extract one level of holes from a container in a region specified by one Traversal, using another.

holesOnOf b l ≡ holesOf (b . l)
 holesOnOf :: Simple Iso a b       -> Simple Iso b b       -> a -> [Context b a]
 holesOnOf :: Simple Lens a b      -> Simple Lens b b      -> a -> [Context b a]
 holesOnOf :: Simple Traversal a b -> Simple Traversal b b -> a -> [Context b a]

para :: Plated a => (a -> [r] -> r) -> a -> rSource

Perform a fold-like computation on each value, technically a paramorphism.

paraparaOf plate

paraOf :: Getting [a] a b a b -> (a -> [r] -> r) -> a -> rSource

Perform a fold-like computation on each value, technically a paramorphism.

paraOf :: Fold a a -> (a -> [r] -> r) -> a -> r

Compos

Provided for compatibility with Björn Bringert's compos library.

Note: Other operations from compos that were inherited by uniplate are not included to avoid having even more redundant names for the same operators. For comparison:

 composOpMonoidfoldMapOf plate
 composOpMPlus f ≡ msumOf (plate . to f)
 composOpdescendover plate
 composOpMdescendMmapMOf plate
 composOpM_descendM_mapMOf_ plate

composOpFold :: Plated a => b -> (b -> b -> b) -> (a -> b) -> a -> bSource

Fold the immediate children of a Plated container.

composOpFold z c f = foldrOf plate (c . f) z

Parts

parts :: Plated a => Simple Lens a [a]Source

The original uniplate combinator, implemented in terms of Plated as a Lens.

partspartsOf plate

The resulting lens is safer to use as it ignores 'over-application' and deals gracefully with under-application, but it is only a proper lens if you don't change the list length!

partsOf :: LensLike (Bazaar c c) a b c c -> Lens a b [c] [c]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.

 partsOf :: Simple Iso a b       -> Simple Lens a [b]
 partsOf :: Simple Lens a b      -> Simple Lens a [b]
 partsOf :: Simple Traversal a b -> Simple Lens a [b]

Unsafe Operations

unsafePartsOf :: LensLike (Bazaar c d) a b c d -> Lens a b [c] [d]Source

unsafePartsOf turns a Traversal into a uniplate (or biplate) family.

If you do not need the types of c and d 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 d's as you were given c's, then the reconstruction of b will result in an error!

 unsafePartsOf :: Iso a b c d       -> Lens a b [c] [d]
 unsafePartsOf :: Lens a b c d      -> Lens a b [c] [d]
 unsafePartsOf :: Traversal a b c d -> Lens a b [c] [d]