effet-0.4.0.0: An Effect System based on Type Classes

Control.Effect.Machinery.TH

Description

This module provides TemplateHaskell functions to generate the handling, lifting and tagging infrastructure for effect type classes.

Synopsis

# Common Generators

Generates the effect handling and lifting infrastructure for an effect which does not have a tag type parameter. Requires the TemplateHaskell language extension.

Consider the following effect type class:

    class Monad m => MyEffect a b c m where
...


makeEffect ''MyEffect then generates three instances for this effect type class (Lift for first-order effects, Control for higher-order effects):

    instance Handle (MyEffect a b c) t m => MyEffect a b c (EachVia (MyEffect a b c : effs) t m) where
...

instance {-# OVERLAPPABLE #-} Find (MyEffect a b c) effs t m => MyEffect a b c (EachVia (other : effs) t m) where
...

instance Lift/Control (MyEffect a b c) t m => MyEffect a b c (EachVia '[] t m) where
...


The first instance indicates that MyEffect was found at the head of the type level list of effects to be handled, so MyEffect is delegated to t.

The second instance indicates that MyEffect was not found at the head of the type level list of effects to be handled, so we must find MyEffect in the tail effs of the type level list.

The third instance indicates that MyEffect could not be found in the type level list of effects to be handled, so the effect must be delegated further down the monad transformer stack in order to find its corresponding effect handler.

Without TemplateHaskell, you have to write these three instances by hand. These instances can also be generated separately, see makeHandler, makeFinder and makeLifter.

Similar to makeEffect, but only generates the effect type class instance for handling an effect.

Similar to makeEffect, but only generates the effect type class instance for finding the effect in the tail of the type level list.

Since: 0.2.0.0

Similar to makeEffect, but only generates the effect type class instance for lifting an effect.

# Tag-based Generators

Generates the effect handling and lifting infrastructure for an effect which has a tag type parameter. It is expected that the tag type parameter is the first type parameter of the effect type class. It is also expected that the names of the effect type class and its methods end with an apostrophe "'". If you want more control over the naming convention, use makeTaggedEffectWith.

In general, this function generates everything that makeEffect does, but also some additional things. Consider the following effect type class:

    class Monad m => MyEffect' tag a b c m where
methodA' :: a -> m ()
methodB' :: b -> m ()
methodC' :: c -> m ()


makeTaggedEffect ''MyEffect' then generates the following additional things:

• A type synonym for the untagged version of MyEffect' with the name MyEffect (note the missing apostrophe).
• Untagged versions of the effect methods, namely methodA, methodB and methodC (note the missing apostrophes).
• An instance of MyEffect' for the type Tagger which does not handle the effect, but simply tags, retags or untags the MyEffect' constraint of a computation.
• Three functions tagMyEffect', retagMyEffect' and untagMyEffect' which make use of the Tagger instance.

As a rule of thumb, whenever you see an apostrophe suffix in the name of a definition somewhere in this library, it has something to do with tags. Most of the time you will use such definitions in combination with the language extension TypeApplications, like:

    ... forall tag ... methodA' @tag ...
tagMyEffect' @"newTag" program
retagMyEffect' @"oldTag" @"newTag" program
untagMyEffect' @"erasedTag" program


All the tag-related definitions can also be generated separately (i.e., without the instances generated by makeEffect), see makeTagger and makeTaggerWith.

makeTaggedEffectWith :: (String -> Q String) -> Name -> Q [Dec] Source #

Similar to makeTaggedEffect, but allows to define a naming convention function for the names of the effect type class and its methods. This function is used to transform the name of a tagged definition (i.e., the type class or its methods) into its untagged counterpart.

The default naming convention is enforced by removeApostrophe, which simply removes the apostrophe "'" at the end of a name.

Similar to makeTaggedEffect, but only generates the tag-related definitions.

makeTaggerWith :: (String -> Q String) -> Name -> Q [Dec] Source #

Similar to makeTaggedEffectWith, but only generates the tag-related definitions.

makeUntagged :: [Name] -> Q [Dec] Source #

Given a list of function names, this function generates untagged versions of them, i.e. it removes the tag type parameters from their type signatures (by applying G) and converts tagged effect type classes found in the signature to their corresponding untagged type synonyms using removeApostrophe.

Since: 0.4.0.0

makeUntaggedWith :: (String -> Q String) -> [Name] -> Q [Dec] Source #

Similar to makeUntagged, but allows to define a naming convention function for the names of the generated functions and the effect type classes modified in the type signatures.

The default naming convention is enforced by removeApostrophe, which simply removes the apostrophe "'" at the end of a name.

Since: 0.4.0.0

# Lifting Convenience

liftL :: EachVia effs t m a -> EachVia (eff ': effs) t m a Source #

Adds an effect eff to the type level list of effects that need to be handled by the transformer t. From a structural point of view, this is analogous to lift in the mtl ecosystem. This function comes in handy when writing the Find-based instance of an effect by hand.

Since: 0.2.0.0

runL :: EachVia (eff ': effs) t m a -> EachVia effs t m a Source #

Removes an effect eff from the type level list of effects that need to be handled by the transformer t. From a structural point of view, this is analogous to the run... functions in the mtl ecosystem. This function comes in handy when writing the Find-based instance of an effect by hand.

Since: 0.2.0.0

# Naming Convention

Extracts the untagged name from a name which is expected to end with "'". In other words, this function removes the suffix "'" from a given name, or fails otherwise.