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

Safe HaskellNone
LanguageHaskell98

Data.Generics.Uniplate

Contents

Description

DEPRECATED Use Data.Generics.Uniplate.Operations instead.

This is the main Uniplate module, which defines all the essential operations in a Haskell 98 compatible manner.

Most functions have an example of a possible use for the function. To illustate, I have used the Expr type as below:

data Expr = Val Int
          | Neg Expr
          | Add Expr Expr

Synopsis

The Class

type UniplateType on = on -> ([on], [on] -> on) Source

The type of replacing all the children of a node

Taking a value, the function should return all the immediate children of the same type, and a function to replace them.

class Uniplate on where Source

The standard Uniplate class, all operations require this

Methods

uniplate :: UniplateType on Source

The underlying method in the class

uniplate (Add (Val 1) (Neg (Val 2))) = ([Val 1, Neg (Val 2)], \[a,b] -> Add a b)
uniplate (Val 1)                     = ([]                  , \[]    -> Val 1  )

The Operations

Queries

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

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] Source

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

children = fst . uniplate

Transformations

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

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, Uniplate on) => (on -> m on) -> on -> m on Source

Monadic variant of transform

rewrite :: Uniplate on => (on -> Maybe on) -> on -> on 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 (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, Uniplate on) => (on -> m (Maybe on)) -> on -> m on Source

Monadic variant of rewrite

descend :: Uniplate on => (on -> on) -> on -> on Source

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.

descendM :: (Monad m, Uniplate on) => (on -> m on) -> on -> m on Source

Monadic variant of descend

Others

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

Return all the contexts and holes.

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

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

The one depth version of contexts

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

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

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