Safe Haskell | Safe-Inferred |
---|

A module of helper functions for use with Alloy. Most of the functions
have versions for pure functions (without suffix), applicative functors (A
suffix) and monads (M suffix) and sometimes the monadic version again with routes.
Generally, only the pure version is documented. The key functions you are likely
to need (or their suffixed versions) are `applyBottomUp`

and `applyBottomUp2`

,
and `listifyDepth`

.

- applyBottomUp :: (Alloy t (OneOp s) BaseOp, Alloy s BaseOp (OneOp s)) => (s -> s) -> t -> t
- applyBottomUpA :: (AlloyA t (OneOpA s) BaseOpA, AlloyA s BaseOpA (OneOpA s), Applicative f) => f (s -> s) -> t -> f t
- applyBottomUpM :: (AlloyA t (OneOpA s) BaseOpA, AlloyA s BaseOpA (OneOpA s), Monad m) => (s -> m s) -> t -> m t
- applyBottomUpMRoute :: (AlloyARoute t (OneOpARoute s) BaseOpARoute, AlloyARoute s BaseOpARoute (OneOpARoute s), Monad m) => ((s, Route s t) -> m s) -> t -> m t
- applyBottomUp2 :: (Alloy t (TwoOp sA sB) BaseOp, Alloy sA BaseOp (TwoOp sA sB), Alloy sB BaseOp (TwoOp sA sB)) => (sA -> sA) -> (sB -> sB) -> t -> t
- applyBottomUpA2 :: (AlloyA t (TwoOpA sA sB) BaseOpA, AlloyA sA BaseOpA (TwoOpA sA sB), AlloyA sB BaseOpA (TwoOpA sA sB), Applicative f) => f (sA -> sA) -> f (sB -> sB) -> t -> f t
- applyBottomUpM2 :: (AlloyA t (TwoOpA sA sB) BaseOpA, AlloyA sA BaseOpA (TwoOpA sA sB), AlloyA sB BaseOpA (TwoOpA sA sB), Monad m) => (sA -> m sA) -> (sB -> m sB) -> t -> m t
- applyBottomUpMRoute2 :: (AlloyARoute t (TwoOpARoute sA sB) BaseOpARoute, AlloyARoute sA BaseOpARoute (TwoOpARoute sA sB), AlloyARoute sB BaseOpARoute (TwoOpARoute sA sB), Monad m) => ((sA, Route sA t) -> m sA) -> ((sB, Route sB t) -> m sB) -> t -> m t
- listifyDepth :: (AlloyA t (OneOpA s) BaseOpA, AlloyA s BaseOpA (OneOpA s)) => (s -> Bool) -> t -> [s]
- listifyDepthRoute :: (AlloyARoute t (OneOpARoute s) BaseOpARoute, AlloyARoute s BaseOpARoute (OneOpARoute s)) => ((s, Route s t) -> Bool) -> t -> [(s, Route s t)]
- checkDepthM :: (Monad m, AlloyA t (OneOpA s) BaseOpA, AlloyA s BaseOpA (OneOpA s)) => (s -> m ()) -> t -> m ()
- checkDepthM2 :: (Monad m, AlloyA t (TwoOpA r s) BaseOpA, AlloyA r BaseOpA (TwoOpA r s), AlloyA s BaseOpA (TwoOpA r s)) => (r -> m ()) -> (s -> m ()) -> t -> m ()
- makeBottomUp :: Alloy t BaseOp opT => opT -> (t -> t) -> t -> t
- makeBottomUpA :: (AlloyA t BaseOpA opT, Applicative f) => opT f -> f (t -> t) -> t -> f t
- makeBottomUpM :: (AlloyA t BaseOpA opT, Monad m) => opT m -> (t -> m t) -> t -> m t
- makeBottomUpMRoute :: (Monad m, AlloyARoute t BaseOpARoute opT) => opT m outer -> ((t, Route t outer) -> m t) -> (t, Route t outer) -> m t

# Functions to easily apply transformations throughout a data structure

applyBottomUp :: (Alloy t (OneOp s) BaseOp, Alloy s BaseOp (OneOp s)) => (s -> s) -> t -> tSource

Given a function that applies to a particular type (`s`

), automatically
applies that function to every instance of `s`

in a larger structure of
type `t`

, performing the transformations in a bottom-up fashion. It does a
depth first traversal in order of a constructor's children, descending
first and applying the function afterwards on the way back up.

This is equivalent to SYB's everywhere function, as it applies the function everywhere it can throughout the data structure. The function will not be applied to the results of your transformation, so the function cannot end up in infinite loop (unless the value you apply the function to is infinite!).

applyBottomUpA :: (AlloyA t (OneOpA s) BaseOpA, AlloyA s BaseOpA (OneOpA s), Applicative f) => f (s -> s) -> t -> f tSource

applyBottomUpM :: (AlloyA t (OneOpA s) BaseOpA, AlloyA s BaseOpA (OneOpA s), Monad m) => (s -> m s) -> t -> m tSource

applyBottomUpMRoute :: (AlloyARoute t (OneOpARoute s) BaseOpARoute, AlloyARoute s BaseOpARoute (OneOpARoute s), Monad m) => ((s, Route s t) -> m s) -> t -> m tSource

applyBottomUp2 :: (Alloy t (TwoOp sA sB) BaseOp, Alloy sA BaseOp (TwoOp sA sB), Alloy sB BaseOp (TwoOp sA sB)) => (sA -> sA) -> (sB -> sB) -> t -> tSource

As `applyBottomUp`

, but applies both functions whereever it can in the
data structure. It is very important that `sA`

is not the same type as
`sB`

-- odd results will occur if they are the same type. It is perfectly
valid for `sA`

to contain `sB`

or vice versa; in this case, the smaller
type will be processed first (as this is a bottom-up traversal) and the
larger type processed later on in the ascent (towards the root) of the
tree.

applyBottomUpA2 :: (AlloyA t (TwoOpA sA sB) BaseOpA, AlloyA sA BaseOpA (TwoOpA sA sB), AlloyA sB BaseOpA (TwoOpA sA sB), Applicative f) => f (sA -> sA) -> f (sB -> sB) -> t -> f tSource

applyBottomUpM2 :: (AlloyA t (TwoOpA sA sB) BaseOpA, AlloyA sA BaseOpA (TwoOpA sA sB), AlloyA sB BaseOpA (TwoOpA sA sB), Monad m) => (sA -> m sA) -> (sB -> m sB) -> t -> m tSource

applyBottomUpMRoute2 :: (AlloyARoute t (TwoOpARoute sA sB) BaseOpARoute, AlloyARoute sA BaseOpARoute (TwoOpARoute sA sB), AlloyARoute sB BaseOpARoute (TwoOpARoute sA sB), Monad m) => ((sA, Route sA t) -> m sA) -> ((sB, Route sB t) -> m sB) -> t -> m tSource

# Listify functions that return lists of items that satisfy given criteria

listifyDepth :: (AlloyA t (OneOpA s) BaseOpA, AlloyA s BaseOpA (OneOpA s)) => (s -> Bool) -> t -> [s]Source

Given a function that examines a type `s`

and gives an answer (True to include
the item in the list, False to drop it), finds all items of type `s`

in some
larger item (of type `t`

) that satisfy this function, listed in depth-first
order.

listifyDepthRoute :: (AlloyARoute t (OneOpARoute s) BaseOpARoute, AlloyARoute s BaseOpARoute (OneOpARoute s)) => ((s, Route s t) -> Bool) -> t -> [(s, Route s t)]Source

# Check functions to apply monadic checks throughout a data structure

checkDepthM :: (Monad m, AlloyA t (OneOpA s) BaseOpA, AlloyA s BaseOpA (OneOpA s)) => (s -> m ()) -> t -> m ()Source

Given a monadic function that operates on items of type `s`

(without modifying
them), applies the function to all items of types `s`

within an item of type
`t`

, in depth-first order.

This can be used, for example, to perform checks on items in an error monad, or to accumulate information in a state monad, or to print out the structure in a writer or IO monad.

checkDepthM2 :: (Monad m, AlloyA t (TwoOpA r s) BaseOpA, AlloyA r BaseOpA (TwoOpA r s), AlloyA s BaseOpA (TwoOpA r s)) => (r -> m ()) -> (s -> m ()) -> t -> m ()Source

# Adding traversal to modifiers

makeBottomUp :: Alloy t BaseOp opT => opT -> (t -> t) -> t -> tSource

Given a set of operations and a modifier function, augments that modifier
function to first descend into the value before then applying the modifier function.
This can be used to perform a bottom-up depth-first traversal of a structure
(see the implementation of `applyBottomUp`

).

You are unlikely to need these functions much yourself; either use `applyBottomUp`

and similar to apply a function everywhere, or if you need more fine-grained
control over the descent, it is usually better to handle the descent in your
own functions.

makeBottomUpA :: (AlloyA t BaseOpA opT, Applicative f) => opT f -> f (t -> t) -> t -> f tSource

makeBottomUpM :: (AlloyA t BaseOpA opT, Monad m) => opT m -> (t -> m t) -> t -> m tSource

makeBottomUpMRoute :: (Monad m, AlloyARoute t BaseOpARoute opT) => opT m outer -> ((t, Route t outer) -> m t) -> (t, Route t outer) -> m tSource