eventuo11y-0.3.1.0: An event-oriented observability library
CopyrightCopyright 2022 Shea Levy.
LicenseApache-2.0
Maintainershea@shealevy.com
Safe HaskellSafe-Inferred
LanguageHaskell2010

Observe.Event.BackendModification

Description

A domain-specific language for modifying the behavior of EventBackends, needed when the caller can't specify the EventBackend to use directly.

The instrumented capability problem

A common approach for polymorphic effect management in Haskell is the "capability pattern", where a function polymorphic in some monad m takes as an argument a value also polymorphic in m that can be used to run a constrained set of effects in m. One example of such a "capability" type would be EventBackend, which for example enables running newEvent in whatever m it's instantiated in. These capabilities are often themselves implemented in terms of other capabilities, and are ultimately concretely instantiated in some base monad (typically IO, or perhaps ST for a pure mock) and then hoisted to the application's monadic context (e.g. hoistEventBackend).

Normally this compose + hoist approach works fine, since any capabilities that are dependencies of the the capability we're hoisting are hidden in its closure. But if a capability depends on an EventBackend for instrumentation, closing over it at creation time causes a problem: at the call-site of the various effects enabled by the capability, we have no way to modify the EventBackend to e.g. be a noop (because we don't need the details of this effect's actions to instrument the calling function effectively) or to have its Events descend from some current Event. Thus, the DSL defined in this module: effects which take some polymorphic capability can *also* take an EventBackendModifier and the capability can modify its captured EventBackend with modifyEventBackend accordingly.

An alternative would be to have each effect in the capability take an EventBackend at the call site. This would foreclose hoisting along an arbitrary natural transformation, since the EventBackend would be in negative position, but constrained hoisting might be possible with MonadUnliftIO or MonadUnlift or MonadBaseControl if we share a base monad, or if we implemented EventBackends in a separate base monad that appears in the type of our capabilities and ensure it's liftable to both our application monad and the capability's base instantiation.

Synopsis

Documentation

data EventBackendModifier r r' where Source #

Modify an EventBackend, chaging its reference type from r to r'

Constructors

Silence :: forall r. EventBackendModifier r ()

Ignore all instrumentation using the EventBackend

SetAncestor

Mark every parentless event as the child of a known Event.

Fields

SetInitialCause

Mark every causeless event as proximately caused by a known Event.

Fields

data EventBackendModifiers r r' Source #

Instances

Instances details
Category EventBackendModifiers Source # 
Instance details

Defined in Observe.Event.BackendModification

Methods

id :: forall (a :: k). EventBackendModifiers a a #

(.) :: forall (b :: k) (c :: k) (a :: k). EventBackendModifiers b c -> EventBackendModifiers a b -> EventBackendModifiers a c #

modifyEventBackend :: Monad m => EventBackendModifiers r r' -> EventBackend m r s -> EventBackend m r' s Source #

Modify an EventBackend according to the given EventBackendModifiers.

This is a right fold, e.g. modifyEventBackend (a . b . id) backend first modifies backend with b and then modifies the result with a.

Simple EventBackendModifiers

setAncestor :: r -> EventBackendModifiers r r Source #

An EventBackendModifiers that marks every parentless event as the child of a known Event.

setInitialCause :: r -> EventBackendModifiers r r Source #

An EventBackendModifiers that marks every causeless event as proximately caused by a known Event.