{-# LANGUAGE ApplicativeDo #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RankNTypes #-}

-- |
-- Description : Interface for implementing EventBackends
-- Copyright   : Copyright 2022 Shea Levy.
-- License     : Apache-2.0
-- Maintainer  : shea@shealevy.com
--
-- This is the primary module needed to write new 'EventBackend's.
module Observe.Event.Backend
  ( -- * Core interface
    EventBackend (..),
    Event (..),
    NewEventArgs (..),
    simpleNewEventArgs,

    -- * Backend composition
    unitEventBackend,
    pairEventBackend,
    noopEventBackend,

    -- * Backend transformation
    hoistEventBackend,
    hoistEvent,
    InjectSelector,
    injectSelector,
    idInjectSelector,
    narrowEventBackend,
    setAncestorEventBackend,
    setInitialCauseEventBackend,
  )
where

import Control.Applicative
import Control.Exception
import Control.Monad.Zip
import Data.Functor

-- | An instrumentation event.
--
-- 'Event's are the core of the instrumenting user's interface
-- to eventuo11y. Typical usage would be to create an 'Event'
-- using v'Observe.Event.withEvent' and add fields to the 'Event' at appropriate
-- points in your code with 'addField'.
--
-- [@m@]: The monad we're instrumenting in.
-- [@r@]: The type of event references. See 'reference'.
-- [@f@]: The type of fields on this event. See 'addField'.
data Event m r f = Event
  { -- | Obtain a reference to an 'Event'.
    --
    -- References are used to link 'Event's together, via the 'newEventParent'
    -- and 'newEventCauses' fields of 'NewEventArgs'.
    --
    -- References can live past when an event has been 'finalize'd.
    --
    -- Code being instrumented should always have @r@ as an unconstrained
    -- type parameter, both because it is an implementation concern for
    -- 'EventBackend's and because references are backend-specific and it
    -- would be an error to reference an event in one backend from an event
    -- in a different backend.
    forall (m :: * -> *) r f. Event m r f -> r
reference :: !r,
    -- | Add a field to an 'Event'.
    --
    -- Fields make up the basic data captured in an event. They should be added
    -- to an 'Event' as the code progresses through various phases of work, and can
    -- be both milestone markers ("we got this far in the process") or more detailed
    -- instrumentation ("we've processed N records").
    --
    -- They are intended to be of a domain specific type per unit of functionality
    -- within an instrumented codebase (but see [DynamicField](https://hackage.haskell.org/package/eventuo11y-json/docs/Observe-Event-Dynamic.html#t:DynamicField)
    -- for a generic option).
    forall (m :: * -> *) r f. Event m r f -> f -> m ()
addField :: !(f -> m ()),
    -- | Mark an 'Event' as finished, perhaps due to an 'Exception'.
    --
    -- In normal usage, this should be automatically called via the use of
    -- the [resource-safe event allocation functions](Observe-Event.html#g:resourcesafe).
    --
    -- This is a no-op if the 'Event' has already been 'finalize'd.
    -- As a result, it is likely pointless to call
    -- 'addField' after this call, though it still may be reasonable to call
    -- 'reference'.
    forall (m :: * -> *) r f.
Event m r f -> Maybe SomeException -> m ()
finalize :: !(Maybe SomeException -> m ())
  }

-- | Hoist an 'Event' along a given natural transformation into a new monad.
hoistEvent :: (forall x. m x -> n x) -> Event m r f -> Event n r f
hoistEvent :: forall (m :: * -> *) (n :: * -> *) r f.
(forall x. m x -> n x) -> Event m r f -> Event n r f
hoistEvent forall x. m x -> n x
nt Event m r f
ev =
  Event m r f
ev
    { addField :: f -> n ()
addField = forall x. m x -> n x
nt forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) r f. Event m r f -> f -> m ()
addField Event m r f
ev,
      finalize :: Maybe SomeException -> n ()
finalize = forall x. m x -> n x
nt forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) r f.
Event m r f -> Maybe SomeException -> m ()
finalize Event m r f
ev
    }

-- | A backend for creating t'Event's.
--
-- Different 'EventBackend's will be used to emit instrumentation to
-- different systems. Multiple backends can be combined with
-- 'Observe.Event.pairEventBackend'.
--
-- A simple 'EventBackend' for logging to a t'System.IO.Handle' can be
-- created with [jsonHandleBackend](https://hackage.haskell.org/package/eventuo11y-json/docs/Observe-Event-Render-JSON-Handle.html#v:jsonHandleBackend).
--
-- From an 'EventBackend', new events can be created via selectors
-- (of type @s f@ for some field type @f@), typically with the
-- [resource-safe allocation functions](Observe-Event.html#g:resourcesafe).
-- Selectors are values which designate the general category of event
-- being created, as well as the type of fields that can be added to it.
-- For example, a web service's selector type may have a @ServicingRequest@
-- constructor, whose field type includes a @ResponseCode@ constructor which
-- records the HTTP status code.
--
-- Selectors are intended to be of a domain specific type per unit of
-- functionality within an instrumented codebase, implemented as a GADT
-- (but see [DynamicEventSelector](https://hackage.haskell.org/package/eventuo11y-json/docs/Observe-Event-Dynamic.html#t:DynamicEventSelector) for a generic option).
--
-- Implementations must ensure that 'EventBackend's and their underlying t'Event's
-- are safe to use across threads.
--
-- [@m@]: The monad we're instrumenting in.
-- [@r@]: The type of event references used in this 'EventBackend'. See 'reference'.
-- [@s@]: The type of event selectors. See 'newEventSelector'.
data EventBackend m r s = EventBackend
  { -- | Create a new 'Event', specified by the given arguments.
    --
    -- Consider the [resource-safe event allocation functions](Observe-Event.html#g:resourcesafe) instead
    -- of calling this directly.
    forall (m :: * -> *) r (s :: * -> *).
EventBackend m r s
-> forall f. NewEventArgs r s f -> m (Event m r f)
newEvent :: forall f. NewEventArgs r s f -> m (Event m r f),
    -- | Create an event which has no duration and is immediately finalized
    -- successfully.
    --
    -- Returns a reference to the event.
    forall (m :: * -> *) r (s :: * -> *).
EventBackend m r s -> forall f. NewEventArgs r s f -> m r
emitImmediateEvent :: forall f. NewEventArgs r s f -> m r
  }

-- | Arguments specifying how an 'Event' should be created.
--
-- See 'simpleNewEventArgs' for a simple case.
data NewEventArgs r s f = NewEventArgs
  { -- | The selector specifying the category of new 'Event' we're creating,
    -- as well as the type of fields that can be added to it (with 'addField').
    --
    -- Selectors are intended to be of a domain specific type per unit of
    -- functionality within an instrumented codebase, implemented as a GADT
    -- (but see [DynamicEventSelector](https://hackage.haskell.org/package/eventuo11y-json/docs/Observe-Event-Dynamic.html#t:DynamicEventSelector) for a generic option).
    forall r (s :: * -> *) f. NewEventArgs r s f -> s f
newEventSelector :: !(s f),
    -- | The parent of the new 'Event', if any.
    --
    -- Typically handled automatically via v'Observe.Event.withEvent'.
    forall r (s :: * -> *) f. NewEventArgs r s f -> Maybe r
newEventParent :: !(Maybe r),
    -- | The proximate causes of the new 'Event', if any.
    forall r (s :: * -> *) f. NewEventArgs r s f -> [r]
newEventCauses :: ![r],
    -- | Fields set at the creation of the 'Event'.
    --
    -- See 'addField'.
    forall r (s :: * -> *) f. NewEventArgs r s f -> [f]
newEventInitialFields :: ![f]
  }

-- | 'NewEventArgs' from a given selector, with no initial fields or explicit references.
--
-- The selector specifies the category of new 'Event' we're creating,
-- as well as the type of fields that can be added to it (with 'addField').
--
-- Selectors are intended to be of a domain specific type per unit of
-- functionality within an instrumented codebase, implemented as a GADT
-- (but see [DynamicEventSelector](https://hackage.haskell.org/package/eventuo11y-json/docs/Observe-Event-Dynamic.html#t:DynamicEventSelector) for a generic option).
simpleNewEventArgs :: s f -> NewEventArgs r s f
simpleNewEventArgs :: forall (s :: * -> *) f r. s f -> NewEventArgs r s f
simpleNewEventArgs s f
sel =
  NewEventArgs
    { newEventSelector :: s f
newEventSelector = s f
sel,
      newEventParent :: Maybe r
newEventParent = forall a. Maybe a
Nothing,
      newEventCauses :: [r]
newEventCauses = [],
      newEventInitialFields :: [f]
newEventInitialFields = []
    }

-- | A no-op 'EventBackend'.
--
-- This can be used if calling instrumented code from an un-instrumented
-- context, or to purposefully ignore instrumentation from some call.
--
-- 'unitEventBackend' is the algebraic unit of 'pairEventBackend'.
unitEventBackend :: Applicative m => EventBackend m () s
unitEventBackend :: forall (m :: * -> *) (s :: * -> *).
Applicative m =>
EventBackend m () s
unitEventBackend = forall (m :: * -> *) r (s :: * -> *).
Applicative m =>
r -> EventBackend m r s
noopEventBackend ()

-- | An 'EventBackend' which sequentially generates 'Observe.Event.Event's in the two given 'EventBackend's.
--
-- This can be used to emit instrumentation in multiple ways (e.g. logs to grafana and metrics on
-- a prometheus HTML page).
pairEventBackend :: Applicative m => EventBackend m a s -> EventBackend m b s -> EventBackend m (a, b) s
pairEventBackend :: forall (m :: * -> *) a (s :: * -> *) b.
Applicative m =>
EventBackend m a s -> EventBackend m b s -> EventBackend m (a, b) s
pairEventBackend EventBackend m a s
x EventBackend m b s
y =
  EventBackend
    { newEvent :: forall f. NewEventArgs (a, b) s f -> m (Event m (a, b) f)
newEvent = \NewEventArgs (a, b) s f
args -> do
        let (NewEventArgs a s f
xArgs, NewEventArgs b s f
yArgs) = forall {r} {r} {s :: * -> *} {f}.
NewEventArgs (r, r) s f -> (NewEventArgs r s f, NewEventArgs r s f)
unzipArgs NewEventArgs (a, b) s f
args
        Event m a f
xEv <- forall (m :: * -> *) r (s :: * -> *).
EventBackend m r s
-> forall f. NewEventArgs r s f -> m (Event m r f)
newEvent EventBackend m a s
x NewEventArgs a s f
xArgs
        Event m b f
yEv <- forall (m :: * -> *) r (s :: * -> *).
EventBackend m r s
-> forall f. NewEventArgs r s f -> m (Event m r f)
newEvent EventBackend m b s
y NewEventArgs b s f
yArgs
        pure $
          Event
            { reference :: (a, b)
reference = (forall (m :: * -> *) r f. Event m r f -> r
reference Event m a f
xEv, forall (m :: * -> *) r f. Event m r f -> r
reference Event m b f
yEv),
              addField :: f -> m ()
addField = \f
f -> forall (m :: * -> *) r f. Event m r f -> f -> m ()
addField Event m a f
xEv f
f forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> forall (m :: * -> *) r f. Event m r f -> f -> m ()
addField Event m b f
yEv f
f,
              finalize :: Maybe SomeException -> m ()
finalize = \Maybe SomeException
me -> forall (m :: * -> *) r f.
Event m r f -> Maybe SomeException -> m ()
finalize Event m a f
xEv Maybe SomeException
me forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> forall (m :: * -> *) r f.
Event m r f -> Maybe SomeException -> m ()
finalize Event m b f
yEv Maybe SomeException
me
            },
      emitImmediateEvent :: forall f. NewEventArgs (a, b) s f -> m (a, b)
emitImmediateEvent = \NewEventArgs (a, b) s f
args -> do
        let (NewEventArgs a s f
xArgs, NewEventArgs b s f
yArgs) = forall {r} {r} {s :: * -> *} {f}.
NewEventArgs (r, r) s f -> (NewEventArgs r s f, NewEventArgs r s f)
unzipArgs NewEventArgs (a, b) s f
args
        a
xRef <- forall (m :: * -> *) r (s :: * -> *).
EventBackend m r s -> forall f. NewEventArgs r s f -> m r
emitImmediateEvent EventBackend m a s
x NewEventArgs a s f
xArgs
        b
yRef <- forall (m :: * -> *) r (s :: * -> *).
EventBackend m r s -> forall f. NewEventArgs r s f -> m r
emitImmediateEvent EventBackend m b s
y NewEventArgs b s f
yArgs
        pure $ (a
xRef, b
yRef)
    }
  where
    unzipArgs :: NewEventArgs (r, r) s f -> (NewEventArgs r s f, NewEventArgs r s f)
unzipArgs NewEventArgs (r, r) s f
args =
      ( NewEventArgs (r, r) s f
args
          { newEventParent :: Maybe r
newEventParent = Maybe r
xParent,
            newEventCauses :: [r]
newEventCauses = [r]
xCauses
          },
        NewEventArgs (r, r) s f
args
          { newEventParent :: Maybe r
newEventParent = Maybe r
yParent,
            newEventCauses :: [r]
newEventCauses = [r]
yCauses
          }
      )
      where
        (Maybe r
xParent, Maybe r
yParent) = forall (m :: * -> *) a b. MonadZip m => m (a, b) -> (m a, m b)
munzip forall a b. (a -> b) -> a -> b
$ forall r (s :: * -> *) f. NewEventArgs r s f -> Maybe r
newEventParent NewEventArgs (r, r) s f
args
        ([r]
xCauses, [r]
yCauses) = forall (m :: * -> *) a b. MonadZip m => m (a, b) -> (m a, m b)
munzip forall a b. (a -> b) -> a -> b
$ forall r (s :: * -> *) f. NewEventArgs r s f -> [r]
newEventCauses NewEventArgs (r, r) s f
args

-- | A no-op 'EventBackend' that can be integrated with other backends.
--
-- This can be used to purposefully ignore instrumentation from some call.
--
-- All events will have the given reference, so can be connected to appropriate
-- events in non-no-op backends, but not in a way that can distinguish between
-- different events from the same no-op backend.
noopEventBackend :: Applicative m => r -> EventBackend m r s
noopEventBackend :: forall (m :: * -> *) r (s :: * -> *).
Applicative m =>
r -> EventBackend m r s
noopEventBackend r
r =
  EventBackend
    { newEvent :: forall f. NewEventArgs r s f -> m (Event m r f)
newEvent = \NewEventArgs r s f
_ ->
        forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$
          Event
            { reference :: r
reference = r
r,
              addField :: f -> m ()
addField = forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. Applicative f => a -> f a
pure (),
              finalize :: Maybe SomeException -> m ()
finalize = forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
            },
      emitImmediateEvent :: forall f. NewEventArgs r s f -> m r
emitImmediateEvent = \NewEventArgs r s f
_ -> forall (f :: * -> *) a. Applicative f => a -> f a
pure r
r
    }

-- | Hoist an 'EventBackend' along a given natural transformation into a new monad.
hoistEventBackend ::
  (Functor m) =>
  (forall x. m x -> n x) ->
  EventBackend m r s ->
  EventBackend n r s
hoistEventBackend :: forall (m :: * -> *) (n :: * -> *) r (s :: * -> *).
Functor m =>
(forall x. m x -> n x) -> EventBackend m r s -> EventBackend n r s
hoistEventBackend forall x. m x -> n x
nt EventBackend m r s
backend =
  EventBackend
    { newEvent :: forall f. NewEventArgs r s f -> n (Event n r f)
newEvent = forall x. m x -> n x
nt forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (m :: * -> *) (n :: * -> *) r f.
(forall x. m x -> n x) -> Event m r f -> Event n r f
hoistEvent forall x. m x -> n x
nt) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) r (s :: * -> *).
EventBackend m r s
-> forall f. NewEventArgs r s f -> m (Event m r f)
newEvent EventBackend m r s
backend,
      emitImmediateEvent :: forall f. NewEventArgs r s f -> n r
emitImmediateEvent = forall x. m x -> n x
nt forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) r (s :: * -> *).
EventBackend m r s -> forall f. NewEventArgs r s f -> m r
emitImmediateEvent EventBackend m r s
backend
    }

-- | Inject a narrower selector and its fields into a wider selector.
--
-- See 'injectSelector' for a simple way to construct one of these.
type InjectSelector s t = forall f. s f -> forall a. (forall g. t g -> (f -> g) -> a) -> a

-- | Construct an 'InjectSelector' with a straightforward injection from @s@ to @t@
injectSelector :: (forall f. s f -> t f) -> InjectSelector s t
injectSelector :: forall (s :: * -> *) (t :: * -> *).
(forall f. s f -> t f) -> InjectSelector s t
injectSelector forall f. s f -> t f
inj s f
sel forall g. t g -> (f -> g) -> a
withInjField = forall g. t g -> (f -> g) -> a
withInjField (forall f. s f -> t f
inj s f
sel) forall a. a -> a
id

-- | The identity 'InjectSelector'
idInjectSelector :: InjectSelector s s
idInjectSelector :: forall (s :: * -> *). InjectSelector s s
idInjectSelector s f
s forall g. s g -> (f -> g) -> a
go = forall g. s g -> (f -> g) -> a
go s f
s forall a. a -> a
id

-- | Narrow an 'EventBackend' to a new selector type via a given injection function.
--
-- A typical usage, where component A calls component B, would be to have A's selector
-- type have a constructor to take any value of B's selector type (and preserve the field)
-- and then call 'narrowEventBackend' with that constructor when invoking functions in B.
narrowEventBackend ::
  (Functor m) =>
  InjectSelector s t ->
  EventBackend m r t ->
  EventBackend m r s
narrowEventBackend :: forall (m :: * -> *) (s :: * -> *) (t :: * -> *) r.
Functor m =>
InjectSelector s t -> EventBackend m r t -> EventBackend m r s
narrowEventBackend InjectSelector s t
inj EventBackend m r t
backend =
  EventBackend
    { newEvent :: forall f. NewEventArgs r s f -> m (Event m r f)
newEvent = \NewEventArgs r s f
args -> InjectSelector s t
inj (forall r (s :: * -> *) f. NewEventArgs r s f -> s f
newEventSelector NewEventArgs r s f
args) \t g
sel' f -> g
injField ->
        forall (m :: * -> *) r (s :: * -> *).
EventBackend m r s
-> forall f. NewEventArgs r s f -> m (Event m r f)
newEvent EventBackend m r t
backend (forall {r} {s :: * -> *} {a} {s :: * -> *} {f}.
NewEventArgs r s a -> s f -> (a -> f) -> NewEventArgs r s f
transformArgs NewEventArgs r s f
args t g
sel' f -> g
injField) forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \Event m r g
ev ->
          Event m r g
ev
            { addField :: f -> m ()
addField = forall (m :: * -> *) r f. Event m r f -> f -> m ()
addField Event m r g
ev forall b c a. (b -> c) -> (a -> b) -> a -> c
. f -> g
injField
            },
      emitImmediateEvent :: forall f. NewEventArgs r s f -> m r
emitImmediateEvent = \NewEventArgs r s f
args -> InjectSelector s t
inj (forall r (s :: * -> *) f. NewEventArgs r s f -> s f
newEventSelector NewEventArgs r s f
args) \t g
sel' f -> g
injField ->
        forall (m :: * -> *) r (s :: * -> *).
EventBackend m r s -> forall f. NewEventArgs r s f -> m r
emitImmediateEvent EventBackend m r t
backend forall a b. (a -> b) -> a -> b
$ forall {r} {s :: * -> *} {a} {s :: * -> *} {f}.
NewEventArgs r s a -> s f -> (a -> f) -> NewEventArgs r s f
transformArgs NewEventArgs r s f
args t g
sel' f -> g
injField
    }
  where
    transformArgs :: NewEventArgs r s a -> s f -> (a -> f) -> NewEventArgs r s f
transformArgs NewEventArgs r s a
args s f
sel' a -> f
injField =
      NewEventArgs r s a
args
        { newEventSelector :: s f
newEventSelector = s f
sel',
          newEventInitialFields :: [f]
newEventInitialFields = a -> f
injField forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall r (s :: * -> *) f. NewEventArgs r s f -> [f]
newEventInitialFields NewEventArgs r s a
args
        }

-- | Transform an 'EventBackend' so all of its 'Event's have a given parent, if they
-- are not given another parent.
setAncestorEventBackend :: r -> EventBackend m r s -> EventBackend m r s
setAncestorEventBackend :: forall r (m :: * -> *) (s :: * -> *).
r -> EventBackend m r s -> EventBackend m r s
setAncestorEventBackend r
parent EventBackend m r s
backend =
  EventBackend
    { newEvent :: forall f. NewEventArgs r s f -> m (Event m r f)
newEvent = forall (m :: * -> *) r (s :: * -> *).
EventBackend m r s
-> forall f. NewEventArgs r s f -> m (Event m r f)
newEvent EventBackend m r s
backend forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {s :: * -> *} {f}. NewEventArgs r s f -> NewEventArgs r s f
transformArgs,
      emitImmediateEvent :: forall f. NewEventArgs r s f -> m r
emitImmediateEvent = forall (m :: * -> *) r (s :: * -> *).
EventBackend m r s -> forall f. NewEventArgs r s f -> m r
emitImmediateEvent EventBackend m r s
backend forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {s :: * -> *} {f}. NewEventArgs r s f -> NewEventArgs r s f
transformArgs
    }
  where
    transformArgs :: NewEventArgs r s f -> NewEventArgs r s f
transformArgs NewEventArgs r s f
args =
      NewEventArgs r s f
args
        { newEventParent :: Maybe r
newEventParent = forall r (s :: * -> *) f. NewEventArgs r s f -> Maybe r
newEventParent NewEventArgs r s f
args forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> forall (f :: * -> *) a. Applicative f => a -> f a
pure r
parent
        }

-- | Transform an 'EventBackend' so all of its 'Event's have the given causes,
-- if they are not given another set of causes.
setInitialCauseEventBackend :: [r] -> EventBackend m r s -> EventBackend m r s
setInitialCauseEventBackend :: forall r (m :: * -> *) (s :: * -> *).
[r] -> EventBackend m r s -> EventBackend m r s
setInitialCauseEventBackend [r]
causes EventBackend m r s
backend =
  EventBackend
    { newEvent :: forall f. NewEventArgs r s f -> m (Event m r f)
newEvent = forall (m :: * -> *) r (s :: * -> *).
EventBackend m r s
-> forall f. NewEventArgs r s f -> m (Event m r f)
newEvent EventBackend m r s
backend forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {s :: * -> *} {f}. NewEventArgs r s f -> NewEventArgs r s f
transformArgs,
      emitImmediateEvent :: forall f. NewEventArgs r s f -> m r
emitImmediateEvent = forall (m :: * -> *) r (s :: * -> *).
EventBackend m r s -> forall f. NewEventArgs r s f -> m r
emitImmediateEvent EventBackend m r s
backend forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {s :: * -> *} {f}. NewEventArgs r s f -> NewEventArgs r s f
transformArgs
    }
  where
    transformArgs :: NewEventArgs r s f -> NewEventArgs r s f
transformArgs NewEventArgs r s f
args =
      NewEventArgs r s f
args
        { newEventCauses :: [r]
newEventCauses = case forall r (s :: * -> *) f. NewEventArgs r s f -> [r]
newEventCauses NewEventArgs r s f
args of
            [] -> [r]
causes
            [r]
l -> [r]
l
        }