| Copyright | (C) 2012-16 Edward Kmett |
|---|---|
| License | BSD-style (see the file LICENSE) |
| Maintainer | Edward Kmett <ekmett@gmail.com> |
| Stability | provisional |
| Portability | Rank2Types |
| Safe Haskell | Trustworthy |
| Language | Haskell98 |
Control.Lens.Plated
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 they 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.
- class Plated a where
- plate :: Traversal' a a
- children :: Plated a => a -> [a]
- rewrite :: Plated a => (a -> Maybe a) -> a -> a
- rewriteOf :: ASetter' a a -> (a -> Maybe a) -> a -> a
- rewriteOn :: Plated a => ASetter s t a a -> (a -> Maybe a) -> s -> t
- rewriteOnOf :: ASetter s t a a -> ASetter' a a -> (a -> Maybe a) -> s -> t
- rewriteM :: (Monad m, Plated a) => (a -> m (Maybe a)) -> a -> m a
- rewriteMOf :: Monad m => LensLike' (WrappedMonad m) a a -> (a -> m (Maybe a)) -> a -> m a
- rewriteMOn :: (Monad m, Plated a) => LensLike (WrappedMonad m) s t a a -> (a -> m (Maybe a)) -> s -> m t
- rewriteMOnOf :: Monad m => LensLike (WrappedMonad m) s t a a -> LensLike' (WrappedMonad m) a a -> (a -> m (Maybe a)) -> s -> m t
- universe :: Plated a => a -> [a]
- universeOf :: Getting [a] a a -> a -> [a]
- universeOn :: Plated a => Getting [a] s a -> s -> [a]
- universeOnOf :: Getting [a] s a -> Getting [a] a a -> s -> [a]
- cosmos :: Plated a => Fold a a
- cosmosOf :: (Applicative f, Contravariant f) => LensLike' f a a -> LensLike' f a a
- cosmosOn :: (Applicative f, Contravariant f, Plated a) => LensLike' f s a -> LensLike' f s a
- cosmosOnOf :: (Applicative f, Contravariant f) => LensLike' f s a -> LensLike' f a a -> LensLike' f s a
- transform :: Plated a => (a -> a) -> a -> a
- transformOf :: ASetter' a a -> (a -> a) -> a -> a
- transformOn :: Plated a => ASetter s t a a -> (a -> a) -> s -> t
- transformOnOf :: ASetter s t a a -> ASetter' a a -> (a -> a) -> s -> t
- transformM :: (Monad m, Plated a) => (a -> m a) -> a -> m a
- transformMOf :: Monad m => LensLike' (WrappedMonad m) a a -> (a -> m a) -> a -> m a
- transformMOn :: (Monad m, Plated a) => LensLike (WrappedMonad m) s t a a -> (a -> m a) -> s -> m t
- transformMOnOf :: Monad m => LensLike (WrappedMonad m) s t a a -> LensLike' (WrappedMonad m) a a -> (a -> m a) -> s -> m t
- contexts :: Plated a => a -> [Context a a a]
- contextsOf :: ATraversal' a a -> a -> [Context a a a]
- contextsOn :: Plated a => ATraversal s t a a -> s -> [Context a a t]
- contextsOnOf :: ATraversal s t a a -> ATraversal' a a -> s -> [Context a a t]
- holes :: Plated a => a -> [Pretext (->) a a a]
- holesOn :: Conjoined p => Over p (Bazaar p a a) s t a a -> s -> [Pretext p a a t]
- holesOnOf :: Conjoined p => LensLike (Bazaar p r r) s t a b -> Over p (Bazaar p r r) a b r r -> s -> [Pretext p r r t]
- para :: Plated a => (a -> [r] -> r) -> a -> r
- paraOf :: Getting (Endo [a]) a a -> (a -> [r] -> r) -> a -> r
- (...) :: (Applicative f, Plated c) => LensLike f s t c c -> Over p f c c a b -> Over p f s t a b
- deep :: (Conjoined p, Applicative f, Plated s) => Traversing p f s s a b -> Over p f s s a b
- composOpFold :: Plated a => b -> (b -> b -> b) -> (a -> b) -> a -> b
- parts :: Plated a => Lens' a [a]
- gplate :: (Generic a, GPlated a (Rep a)) => Traversal' a a
- class GPlated a g
Uniplate
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.Lens.Plated
import Data.Data
import Data.Data.Lens (uniplate)
data Expr = ValInt| Neg Expr | Add Expr Expr deriving (Eq,Ord,Show,Read,Data,Typeable)
instancePlatedExpr whereplatef (Neg e) = Neg<$>f eplatef (Add a b) = Add<$>f a<*>f bplate_ a =purea
or
instancePlatedExpr whereplate=uniplate
Example 2:
import Control.Applicative
import Control.Lens
import Control.Lens.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)
instancePlated(Tree a) whereplatef (Bin l r) = Bin<$>f l<*>f rplate_ t =puret
or
instanceDataa =>Plated(Tree a) whereplate=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.
toListOfbiplate≡universeOnOfbiplateignored
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.
Minimal complete definition
Nothing
Methods
plate :: Traversal' a a Source
Instances
| Plated Exp Source | |
| Plated Pat Source | |
| Plated Type Source | |
| Plated Dec Source | |
| Plated Stmt Source | |
| Plated Con Source | |
| Plated [a] Source | |
| Plated (Tree a) Source | |
| Traversable f => Plated (Cofree f a) Source | |
| Traversable f => Plated (F f a) Source | |
| Traversable f => Plated (Free f a) Source | |
| (Traversable f, Traversable w) => Plated (CofreeT f w a) Source | |
| (Traversable f, Traversable m) => Plated (FreeT f m a) Source |
Uniplate Combinators
rewrite :: Plated a => (a -> Maybe a) -> a -> a Source
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(rewriter 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 which performs both rewrites until a fixed point.mplus g a
rewriteOf :: ASetter' a a -> (a -> Maybe a) -> a -> a Source
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) (universeOfl (rewriteOfl 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 which performs both rewrites until a fixed point.mplus g a
rewriteOf::Iso'a a -> (a ->Maybea) -> a -> arewriteOf::Lens'a a -> (a ->Maybea) -> a -> arewriteOf::Traversal'a a -> (a ->Maybea) -> a -> arewriteOf::Setter'a a -> (a ->Maybea) -> a -> a
rewriteOn :: Plated a => ASetter s t a a -> (a -> Maybe a) -> s -> t Source
Rewrite recursively over part of a larger structure.
rewriteOn::Plateda =>Iso's a -> (a ->Maybea) -> s -> srewriteOn::Plateda =>Lens's a -> (a ->Maybea) -> s -> srewriteOn::Plateda =>Traversal's a -> (a ->Maybea) -> s -> srewriteOn::Plateda =>ASetter's a -> (a ->Maybea) -> s -> s
rewriteOnOf :: ASetter s t a a -> ASetter' a a -> (a -> Maybe a) -> s -> t Source
Rewrite recursively over part of a larger structure using a specified Setter.
rewriteOnOf::Iso's a ->Iso'a a -> (a ->Maybea) -> s -> srewriteOnOf::Lens's a ->Lens'a a -> (a ->Maybea) -> s -> srewriteOnOf::Traversal's a ->Traversal'a a -> (a ->Maybea) -> s -> srewriteOnOf::Setter's a ->Setter'a a -> (a ->Maybea) -> s -> s
rewriteM :: (Monad m, Plated a) => (a -> m (Maybe a)) -> a -> m a Source
Rewrite by applying a monadic rule everywhere you can. Ensures that the rule cannot be applied anywhere in the result.
rewriteMOf :: Monad m => LensLike' (WrappedMonad m) a a -> (a -> m (Maybe a)) -> a -> m a Source
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 a) => LensLike (WrappedMonad m) s t a a -> (a -> m (Maybe a)) -> s -> m t Source
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) s t a a -> LensLike' (WrappedMonad m) a a -> (a -> m (Maybe a)) -> s -> m t Source
universe :: Plated a => a -> [a] Source
Retrieve all of the transitive descendants of a Plated container, including itself.
universeOf :: Getting [a] a a -> 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::Folda a -> a -> [a]
universeOn :: Plated a => Getting [a] s a -> s -> [a] Source
universeOnOf :: Getting [a] s a -> Getting [a] a a -> s -> [a] 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.
toListOfl ≡universeOnOflignored
cosmos :: Plated a => Fold a a Source
Fold over all transitive descendants of a Plated container, including itself.
cosmosOf :: (Applicative f, Contravariant f) => LensLike' f a a -> LensLike' f a a Source
cosmosOn :: (Applicative f, Contravariant f, Plated a) => LensLike' f s a -> LensLike' f s a Source
cosmosOnOf :: (Applicative f, Contravariant f) => LensLike' f s a -> LensLike' f a a -> LensLike' f s a Source
transformOf :: ASetter' a a -> (a -> a) -> a -> a Source
Transform every element by recursively applying a given Setter in a bottom-up manner.
transformOf::Traversal'a a -> (a -> a) -> a -> atransformOf::Setter'a a -> (a -> a) -> a -> a
transformOn :: Plated a => ASetter s t a a -> (a -> a) -> s -> t Source
Transform every element in the tree in a bottom-up manner over a region indicated by a Setter.
transformOn::Plateda =>Traversal's a -> (a -> a) -> s -> stransformOn::Plateda =>Setter's a -> (a -> a) -> s -> s
transformOnOf :: ASetter s t a a -> ASetter' a a -> (a -> a) -> s -> t Source
Transform every element in a region indicated by a Setter by recursively applying another Setter
in a bottom-up manner.
transformOnOf::Setter's a ->Traversal'a a -> (a -> a) -> s -> stransformOnOf::Setter's a ->Setter'a a -> (a -> a) -> s -> s
transformM :: (Monad m, Plated a) => (a -> m a) -> a -> m a Source
Transform every element in the tree, in a bottom-up manner, monadically.
transformMOf :: Monad m => LensLike' (WrappedMonad m) a a -> (a -> m a) -> a -> m a Source
Transform every element in a tree using a user supplied Traversal in a bottom-up manner with a monadic effect.
transformMOf::Monadm =>Traversal'a a -> (a -> m a) -> a -> m a
transformMOn :: (Monad m, Plated a) => LensLike (WrappedMonad m) s t a a -> (a -> m a) -> s -> m t Source
Transform every element in the tree in a region indicated by a supplied Traversal, in a bottom-up manner, monadically.
transformMOn:: (Monadm,Plateda) =>Traversal's a -> (a -> m a) -> s -> m s
transformMOnOf :: Monad m => LensLike (WrappedMonad m) s t a a -> LensLike' (WrappedMonad m) a a -> (a -> m a) -> s -> m t Source
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::Monadm =>Traversal's a ->Traversal'a a -> (a -> m a) -> s -> m s
contextsOf :: ATraversal' 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 =universeOfl x==mappos(contextsOfl x) propId l x =all(==x) [extractw | w <-contextsOfl x]
contextsOf::Traversal'a a -> a -> [Contexta a a]
contextsOn :: Plated a => ATraversal s t a a -> s -> [Context a a t] 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.
contextsOnb ≡contextsOnOfbplate
contextsOn::Plateda =>Traversal's a -> s -> [Contexta a s]
contextsOnOf :: ATraversal s t a a -> ATraversal' a a -> s -> [Context a a t] 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::Traversal's a ->Traversal'a a -> s -> [Contexta a s]
holes :: Plated a => a -> [Pretext (->) 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 =childrenl x==mappos(holesl x) propId x =all(==x) [extractw | w <-holesl x]
holes=holesOfplate
holesOn :: Conjoined p => Over p (Bazaar p a a) s t a a -> s -> [Pretext p a a t] Source
An alias for holesOf, provided for consistency with the other combinators.
holesOn≡holesOf
holesOn::Iso's a -> s -> [Pretext(->) a a s]holesOn::Lens's a -> s -> [Pretext(->) a a s]holesOn::Traversal's a -> s -> [Pretext(->) a a s]holesOn::IndexedLens'i s a -> s -> [Pretext(Indexedi) a a s]holesOn::IndexedTraversal'i s a -> s -> [Pretext(Indexedi) a a s]
holesOnOf :: Conjoined p => LensLike (Bazaar p r r) s t a b -> Over p (Bazaar p r r) a b r r -> s -> [Pretext p r r t] Source
Extract one level of holes from a container in a region specified by one Traversal, using another.
holesOnOfb l ≡holesOf(b.l)
holesOnOf::Iso's a ->Iso'a a -> s -> [Pretext(->) a a s]holesOnOf::Lens's a ->Lens'a a -> s -> [Pretext(->) a a s]holesOnOf::Traversal's a ->Traversal'a a -> s -> [Pretext(->) a a s]holesOnOf::Lens's a ->IndexedLens'i a a -> s -> [Pretext(Indexedi) a a s]holesOnOf::Traversal's a ->IndexedTraversal'i a a -> s -> [Pretext(Indexedi) a a s]
(...) :: (Applicative f, Plated c) => LensLike f s t c c -> Over p f c c a b -> Over p f s t a b infixr 9 Source
Compose through a plate
deep :: (Conjoined p, Applicative f, Plated s) => Traversing p f s s a b -> Over p f s s a b Source
Try to apply a traversal to all transitive descendants of a Plated container, but
do not recurse through matching descendants.
deep::Plateds =>Folds a ->Folds adeep::Plateds =>IndexedFolds a ->IndexedFolds adeep::Plateds =>Traversals s a b ->Traversals s a bdeep::Plateds =>IndexedTraversals s a b ->IndexedTraversals s a b
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:
composOpMonoid≡foldMapOfplatecomposOpMPlusf ≡msumOf(plate.tof)composOp≡descend≡overplatecomposOpM≡descendM≡mapMOfplatecomposOpM_≡descendM_≡mapMOf_plate
composOpFold :: Plated a => b -> (b -> b -> b) -> (a -> b) -> a -> b Source
Fold the immediate children of a Plated container.
composOpFoldz c f =foldrOfplate(c.f) z
Parts
Generics
Minimal complete definition
gplate'