effet-0.1.0.0: An Effect System based on Type Classes
Copyright(c) Michael Szvetits 2020
LicenseBSD3 (see the file LICENSE)
Maintainertypedbyte@qualified.name
Stabilitystable
Portabilityportable
Safe HaskellNone
LanguageHaskell2010

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

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

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 two 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 (Via (MyEffect a b c) t m) where
      ...

    instance {-# OVERLAPPABLE #-} Lift/Control (MyEffect a b c) t m => MyEffect a b c (Via eff t m) where
      ...

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

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

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

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

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

Tag-based Generators

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

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.

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

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.

Naming Convention

removeApostrophe :: String -> Q String Source #

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.