Data.Generics.Uniplate.DataOnly

uniplate-1.6.13: Help writing simple, concise and fast generic operations.

Safe Haskell | None
Language | Haskell2010

Data.Generics.Uniplate.DataOnly

Contents

- Orphan instances

Description

This module functions identically to Data.Generics.Uniplate.Data, but instead of using the standard `Uniplate` / `Biplate` classes defined in Data.Generics.Uniplate.Operations it uses a local copy.

Only use this module if you are using both `Data` and `Direct` instances in the same project and they are conflicting.

Synopsis

- class Uniplate on where
  - uniplate :: on -> (Str on, Str on -> on)
  - descend :: (on -> on) -> on -> on
  - descendM :: Applicative m => (on -> m on) -> on -> m on
- class Uniplate to => Biplate from to where
  - biplate :: from -> (Str to, Str to -> from)
  - descendBi :: (to -> to) -> from -> from
  - descendBiM :: Applicative m => (to -> m to) -> from -> m from
- universe :: Uniplate on => on -> [on]
- children :: Uniplate on => on -> [on]
- transform :: Uniplate on => (on -> on) -> on -> on
- transformM :: (Monad m, Applicative m, Uniplate on) => (on -> m on) -> on -> m on
- rewrite :: Uniplate on => (on -> Maybe on) -> on -> on
- rewriteM :: (Monad m, Applicative m, Uniplate on) => (on -> m (Maybe on)) -> on -> m on
- contexts :: Uniplate on => on -> [(on, on -> on)]
- holes :: Uniplate on => on -> [(on, on -> on)]
- para :: Uniplate on => (on -> [r] -> r) -> on -> r
- universeBi :: Biplate from to => from -> [to]
- childrenBi :: Biplate from to => from -> [to]
- transformBi :: Biplate from to => (to -> to) -> from -> from
- transformBiM :: (Monad m, Applicative m, Biplate from to) => (to -> m to) -> from -> m from
- rewriteBi :: Biplate from to => (to -> Maybe to) -> from -> from
- rewriteBiM :: (Monad m, Applicative m, Biplate from to) => (to -> m (Maybe to)) -> from -> m from
- contextsBi :: Biplate from to => from -> [(to, to -> from)]
- holesBi :: Biplate from to => from -> [(to, to -> from)]
- transformBis :: Data a => [[Transformer]] -> a -> a
- data Transformer
- transformer :: Data a => (a -> a) -> Transformer

# Documentation

class Uniplate on where #

The standard Uniplate class, all operations require this. All definitions must define `uniplate`, while `descend` and `descendM` are optional.

Minimal complete definition

uniplate

Methods

uniplate :: on -> (Str on, Str on -> on) #

The underlying method in the class. Taking a value, the function should return all the immediate children of the same type, and a function to replace them.

Given `uniplate x = (cs, gen)`

`cs` should be a `Str on`, constructed of `Zero`, `One` and `Two`, containing all `x`'s direct children of the same type as `x`. `gen` should take a `Str on` with exactly the same structure as `cs`, and generate a new element with the children replaced.

Example instance:

    instance Uniplate Expr where
        uniplate (Val i  ) = (Zero               , \Zero                  -> Val i  )
        uniplate (Neg a  ) = (One a              , \(One a)               -> Neg a  )
        uniplate (Add a b) = (Two (One a) (One b), \(Two (One a) (One b)) -> Add a b)

descend :: (on -> on) -> on -> on #

Perform a transformation on all the immediate children, then combine them back. This operation allows additional information to be passed downwards, and can be used to provide a top-down transformation. This function can be defined explicitly, or can be provided by automatically in terms of `uniplate`.

For example, on the sample type, we could write:

    descend f (Val i  ) = Val i
    descend f (Neg a  ) = Neg (f a)
    descend f (Add a b) = Add (f a) (f b)

descendM :: Applicative m => (on -> m on) -> on -> m on #

Applicative variant of `descend`

#### Instances

Instances details

Data a => Uniplate a # |
Instance details Defined in Data.Generics.Uniplate.DataOnly Methods uniplate :: a -> (Str a, Str a -> a) # descend :: (a -> a) -> a -> a # descendM :: Applicative m => (a -> m a) -> a -> m a #

class Uniplate to => Biplate from to where #

Children are defined as the top-most items of type to starting at the root. All instances must define `biplate`, while `descendBi` and `descendBiM` are optional.

Minimal complete definition

biplate

Methods

biplate :: from -> (Str to, Str to -> from) #

Return all the top most children of type `to` within `from`.

If `from == to` then this function should return the root as the single child.

descendBi :: (to -> to) -> from -> from #

Like `descend` but with more general types. If `from == to` then this function does not descend. Therefore, when writing definitions it is highly unlikely that this function should be used in the recursive case. A common pattern is to first match the types using `descendBi`, then continue the recursion with `descend`.

descendBiM :: Applicative m => (to -> m to) -> from -> m from #

#### Instances

Instances details

(Data a, Data b, Uniplate b) => Biplate a b # |
Instance details Defined in Data.Generics.Uniplate.DataOnly Methods biplate :: a -> (Str b, Str b -> a) # descendBi :: (b -> b) -> a -> a # descendBiM :: Applicative m => (b -> m b) -> a -> m a #

universe :: Uniplate on => on -> [on] #

Get all the children of a node, including itself and all children.

    universe (Add (Val 1) (Neg (Val 2))) =
        [Add (Val 1) (Neg (Val 2)), Val 1, Neg (Val 2), Val 2]

This method is often combined with a list comprehension, for example:

    vals x = [i | Val i <- universe x]

children :: Uniplate on => on -> [on] #

Get the direct children of a node. Usually using `universe` is more appropriate.

transform :: Uniplate on => (on -> on) -> on -> on #

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

For example, replacing negative literals with literals:

    negLits = transform f
       where f (Neg (Lit i)) = Lit (negate i)
             f x = x

transformM :: (Monad m, Applicative m, Uniplate on) => (on -> m on) -> on -> m on #

Applicative variant of `transform`

rewrite :: Uniplate on => (on -> Maybe on) -> on -> on #

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 `f `mplus` g` which performs both rewrites until a fixed point.

rewriteM :: (Monad m, Applicative m, Uniplate on) => (on -> m (Maybe on)) -> on -> m on #

Applicative variant of `rewrite`

contexts :: Uniplate on => on -> [(on, on -> on)] #

Return all the contexts and holes.

    universe x == map fst (contexts x)
    all (== x) [b a | (a,b) <- contexts x]

holes :: Uniplate on => on -> [(on, on -> on)] #

The one depth version of `contexts`

    children x == map fst (holes x)
    all (== x) [b a | (a,b) <- holes x]

para :: Uniplate on => (on -> [r] -> r) -> on -> r #

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

universeBi :: Biplate from to => from -> [to] #

childrenBi :: Biplate from to => from -> [to] #

Return the children of a type. If `to == from` then it returns the original element (in contrast to `children`)

transformBi :: Biplate from to => (to -> to) -> from -> from #

transformBiM :: (Monad m, Applicative m, Biplate from to) => (to -> m to) -> from -> m from #

rewriteBi :: Biplate from to => (to -> Maybe to) -> from -> from #

rewriteBiM :: (Monad m, Applicative m, Biplate from to) => (to -> m (Maybe to)) -> from -> m from #

contextsBi :: Biplate from to => from -> [(to, to -> from)] #

holesBi :: Biplate from to => from -> [(to, to -> from)] #

transformBis :: Data a => [[Transformer]] -> a -> a #

Apply a sequence of transformations in order. This function obeys the equivalence:

    transformBis [[transformer f],[transformer g],...] == transformBi f . transformBi g . ...

Each item of type `[Transformer]` is applied in turn, right to left. Within each `[Transformer]`, the individual `Transformer` values may be interleaved.

The implementation will attempt to perform fusion, and avoid walking any part of the data structure more than necessary. To further improve performance, you may wish to partially apply the first argument, which will calculate information about the relationship between the transformations.

data Transformer #

transformer :: Data a => (a -> a) -> Transformer #

Wrap up a `(a -> a)` transformation function, to use with `transformBis`

# Orphan instances

Data a => Uniplate a # |
Instance details Methods uniplate :: a -> (Str a, Str a -> a) # descend :: (a -> a) -> a -> a # descendM :: Applicative m => (a -> m a) -> a -> m a #
(Data a, Data b, Uniplate b) => Biplate a b # |
Instance details Methods biplate :: a -> (Str b, Str b -> a) # descendBi :: (b -> b) -> a -> a # descendBiM :: Applicative m => (b -> m b) -> a -> m a #