-- Copyright 2024 Shea Levy
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE UnicodeSyntax #-}
{-# OPTIONS_HADDOCK not-home #-}

{- |
Description : Interface for implementing EventBackends
Copyright   : Copyright 2024 Shea Levy.
License     : Apache-2.0
Maintainer  : shea@shealevy.com

This is the primary module needed to write a new 'EventBackend' and make it an 'EventBackendIn' relevant monads.
-}
module Observe.Event.Backend
  ( -- * Defining backends
    EventBackend (..)
  , EventBackendIn (..)
  , EventParams (..)

    -- ** Defining event types
  , Event (..)
  , EventIn (..)

    -- * Selectors
  , Selectors (..)
  , SubSelector
  )
where

import Control.Exception
import Control.Monad.Trans.Class
import Control.Monad.Trans.Class.Parametric
import Control.Monad.Zip
import Data.Functor.Const
import Data.Functor.Parametric
import Data.Functor.Product
import Data.Kind
import Data.Proxy
import Observe.Event.Compat

{- | A resource allowing creation of new 'Event's.

It must be an 'EventBackendIn' some monad to be useful.
-}
class (Event (BackendEvent backend))  EventBackend (backend  Type) where
  -- | The 'Event' type this 'EventBackend' can generate.
  --
  -- 'Event's are parameterized by the type of [fields](Observe-Event.html#g:selectorAndField)
  -- they support.
  type BackendEvent backend  Type  Type

  -- | The root of the [selector tree](Observe-Event.html#g:selectorAndField) this 'EventBackend' supports.
  type RootSelector backend  Type  Type

-- | An 'EventBackend' which can be used in a given @m@onad
class (EventBackend backend, EventIn m (BackendEvent backend))  EventBackendIn m backend where
  -- | Create a new 'Event' with the given @field@ type.
  --
  -- Callers must ensure the resulting 'Event' is
  -- 'finalize'd; the higher-level [event initialization functions](Observe-Event.html#g:init)
  -- take care of this for you.
  newEvent
     backend
     EventParams (RootSelector backend) field (EventReference (BackendEvent backend))
    -- ^ Specify the event, matching the appropriate [selector](Observe-Event.html#g:selectorAndField)
    -- type for this 'EventBackend'.
     m (BackendEvent backend field)

  -- | Create an event which has no duration.
  --
  -- Returns a reference to the event.
  newInstantEvent
     backend
     EventParams (RootSelector backend) field (EventReference (BackendEvent backend))
     m (EventReference (BackendEvent backend))

-- | Parameters specifying a new 'Event'
data EventParams selector field reference = EventParams
  { forall (selector :: * -> *) field reference.
EventParams selector field reference -> Selectors selector field
selectors  !(Selectors selector field)
  -- ^ [Select](Observe-Event.html#g:selectorAndField) the type of the new 'Event'
  , forall (selector :: * -> *) field reference.
EventParams selector field reference -> Maybe reference
parent  !(Maybe reference)
  -- ^ A [reference](Observe-Event.html#g:relationships) to the parent of the new 'Event', if it has one.
  , forall (selector :: * -> *) field reference.
EventParams selector field reference -> [reference]
causes  ![reference]
  -- ^ [References](Observe-Event.html#g:relationships) to the (proximate) causes of the new 'Event', if any.
  , forall (selector :: * -> *) field reference.
EventParams selector field reference -> [field]
initialFields  ![field]
  -- ^ Fields to add to the 'Event' upon initialization.
  --
  -- This is especially useful in conjunction with 'newInstantEvent'
  }

-- | An 'EventBackend' that does nothing.
instance EventBackend (Proxy (selector  Type  Type)) where
  type BackendEvent (Proxy selector) = Const ()
  type RootSelector (Proxy selector) = selector

-- | An 'EventBackend' that does nothing.
instance (Monad m, ParametricFunctor m)  EventBackendIn m (Proxy (selector  Type  Type)) where
  newEvent :: forall field.
Proxy selector
-> EventParams
     (RootSelector (Proxy selector))
     field
     (EventReference (BackendEvent (Proxy selector)))
-> m (BackendEvent (Proxy selector) field)
newEvent Proxy selector
_ EventParams
  (RootSelector (Proxy selector))
  field
  (EventReference (BackendEvent (Proxy selector)))
_ = BackendEvent (Proxy selector) field
-> m (BackendEvent (Proxy selector) field)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (BackendEvent (Proxy selector) field
 -> m (BackendEvent (Proxy selector) field))
-> BackendEvent (Proxy selector) field
-> m (BackendEvent (Proxy selector) field)
forall a b. (a -> b) -> a -> b
$ () -> Const () field
forall {k} a (b :: k). a -> Const a b
Const ()
  newInstantEvent :: forall field.
Proxy selector
-> EventParams
     (RootSelector (Proxy selector))
     field
     (EventReference (BackendEvent (Proxy selector)))
-> m (EventReference (BackendEvent (Proxy selector)))
newInstantEvent Proxy selector
_ EventParams
  (RootSelector (Proxy selector))
  field
  (EventReference (BackendEvent (Proxy selector)))
_ = () -> m ()
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()

{- | Combine two 'EventBackend's.

All operations are performed sequentially, with no
exception safety between calls.
-}
instance (EventBackend b1, EventBackend b2, RootSelector b1 ~ RootSelector b2)  EventBackend (b1, b2) where
  type BackendEvent (b1, b2) = Product (BackendEvent b1) (BackendEvent b2)
  type RootSelector (b1, b2) = RootSelector b1

{- | Combine two 'EventBackend's.

All operations are performed sequentially, with no
exception safety between calls.
-}
instance (EventBackendIn m b1, EventBackendIn m b2, RootSelector b1 ~ RootSelector b2)  EventBackendIn m (b1, b2) where
  newEvent :: forall field.
(b1, b2)
-> EventParams
     (RootSelector (b1, b2))
     field
     (EventReference (BackendEvent (b1, b2)))
-> m (BackendEvent (b1, b2) field)
newEvent (b1
b1, b2
b2) EventParams
  (RootSelector (b1, b2))
  field
  (EventReference (BackendEvent (b1, b2)))
args = BackendEvent b1 field
-> BackendEvent b2 field
-> Product (BackendEvent b1) (BackendEvent b2) field
forall {k} (f :: k -> *) (g :: k -> *) (a :: k).
f a -> g a -> Product f g a
Pair (BackendEvent b1 field
 -> BackendEvent b2 field
 -> Product (BackendEvent b1) (BackendEvent b2) field)
-> m (BackendEvent b1 field)
-> m (BackendEvent b2 field
      -> Product (BackendEvent b1) (BackendEvent b2) field)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> b1
-> EventParams
     (RootSelector b1) field (EventReference (BackendEvent b1))
-> m (BackendEvent b1 field)
forall field.
b1
-> EventParams
     (RootSelector b1) field (EventReference (BackendEvent b1))
-> m (BackendEvent b1 field)
forall (m :: * -> *) backend field.
EventBackendIn m backend =>
backend
-> EventParams
     (RootSelector backend)
     field
     (EventReference (BackendEvent backend))
-> m (BackendEvent backend field)
newEvent b1
b1 EventParams
  (RootSelector b1) field (EventReference (BackendEvent b1))
EventParams
  (RootSelector b2) field (EventReference (BackendEvent b1))
args1 m (BackendEvent b2 field
   -> Product (BackendEvent b1) (BackendEvent b2) field)
-> m (BackendEvent b2 field)
-> m (Product (BackendEvent b1) (BackendEvent b2) field)
forall a b. m (a -> b) -> m a -> m b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> b2
-> EventParams
     (RootSelector b2) field (EventReference (BackendEvent b2))
-> m (BackendEvent b2 field)
forall field.
b2
-> EventParams
     (RootSelector b2) field (EventReference (BackendEvent b2))
-> m (BackendEvent b2 field)
forall (m :: * -> *) backend field.
EventBackendIn m backend =>
backend
-> EventParams
     (RootSelector backend)
     field
     (EventReference (BackendEvent backend))
-> m (BackendEvent backend field)
newEvent b2
b2 EventParams
  (RootSelector b2) field (EventReference (BackendEvent b2))
args2
   where
    (EventParams
  (RootSelector b2) field (EventReference (BackendEvent b1))
args1, EventParams
  (RootSelector b2) field (EventReference (BackendEvent b2))
args2) = EventParams
  (RootSelector b2)
  field
  (EventReference (BackendEvent b1),
   EventReference (BackendEvent b2))
-> (EventParams
      (RootSelector b2) field (EventReference (BackendEvent b1)),
    EventParams
      (RootSelector b2) field (EventReference (BackendEvent b2)))
forall (selector :: * -> *) field r1 r2.
EventParams selector field (r1, r2)
-> (EventParams selector field r1, EventParams selector field r2)
unwrapPairParams EventParams
  (RootSelector b2)
  field
  (EventReference (BackendEvent b1),
   EventReference (BackendEvent b2))
EventParams
  (RootSelector (b1, b2))
  field
  (EventReference (BackendEvent (b1, b2)))
args
  newInstantEvent :: forall field.
(b1, b2)
-> EventParams
     (RootSelector (b1, b2))
     field
     (EventReference (BackendEvent (b1, b2)))
-> m (EventReference (BackendEvent (b1, b2)))
newInstantEvent (b1
b1, b2
b2) EventParams
  (RootSelector (b1, b2))
  field
  (EventReference (BackendEvent (b1, b2)))
args = (,) (EventReference (BackendEvent b1)
 -> EventReference (BackendEvent b2)
 -> (EventReference (BackendEvent b1),
     EventReference (BackendEvent b2)))
-> m (EventReference (BackendEvent b1))
-> m (EventReference (BackendEvent b2)
      -> (EventReference (BackendEvent b1),
          EventReference (BackendEvent b2)))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> b1
-> EventParams
     (RootSelector b1) field (EventReference (BackendEvent b1))
-> m (EventReference (BackendEvent b1))
forall field.
b1
-> EventParams
     (RootSelector b1) field (EventReference (BackendEvent b1))
-> m (EventReference (BackendEvent b1))
forall (m :: * -> *) backend field.
EventBackendIn m backend =>
backend
-> EventParams
     (RootSelector backend)
     field
     (EventReference (BackendEvent backend))
-> m (EventReference (BackendEvent backend))
newInstantEvent b1
b1 EventParams
  (RootSelector b1) field (EventReference (BackendEvent b1))
EventParams
  (RootSelector b2) field (EventReference (BackendEvent b1))
args1 m (EventReference (BackendEvent b2)
   -> (EventReference (BackendEvent b1),
       EventReference (BackendEvent b2)))
-> m (EventReference (BackendEvent b2))
-> m (EventReference (BackendEvent b1),
      EventReference (BackendEvent b2))
forall a b. m (a -> b) -> m a -> m b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> b2
-> EventParams
     (RootSelector b2) field (EventReference (BackendEvent b2))
-> m (EventReference (BackendEvent b2))
forall field.
b2
-> EventParams
     (RootSelector b2) field (EventReference (BackendEvent b2))
-> m (EventReference (BackendEvent b2))
forall (m :: * -> *) backend field.
EventBackendIn m backend =>
backend
-> EventParams
     (RootSelector backend)
     field
     (EventReference (BackendEvent backend))
-> m (EventReference (BackendEvent backend))
newInstantEvent b2
b2 EventParams
  (RootSelector b2) field (EventReference (BackendEvent b2))
args2
   where
    (EventParams
  (RootSelector b2) field (EventReference (BackendEvent b1))
args1, EventParams
  (RootSelector b2) field (EventReference (BackendEvent b2))
args2) = EventParams
  (RootSelector b2)
  field
  (EventReference (BackendEvent b1),
   EventReference (BackendEvent b2))
-> (EventParams
      (RootSelector b2) field (EventReference (BackendEvent b1)),
    EventParams
      (RootSelector b2) field (EventReference (BackendEvent b2)))
forall (selector :: * -> *) field r1 r2.
EventParams selector field (r1, r2)
-> (EventParams selector field r1, EventParams selector field r2)
unwrapPairParams EventParams
  (RootSelector b2)
  field
  (EventReference (BackendEvent b1),
   EventReference (BackendEvent b2))
EventParams
  (RootSelector (b1, b2))
  field
  (EventReference (BackendEvent (b1, b2)))
args

{- | Lift an 'EventBackend' into a 'MonadTrans'formed @m@onad.

Note that this instance is [incoherent](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/instances.html#overlapping-instances),
so it can be overridden for your @backend@ if need be. This instance will still be used in monad-generic code, however.
-}
instance {-# INCOHERENT #-} (EventBackendIn m backend, ParametricMonadTrans t, MonadTransMonadConstraint t m)  EventBackendIn (t m) backend where
  newEvent :: forall field.
backend
-> EventParams
     (RootSelector backend)
     field
     (EventReference (BackendEvent backend))
-> t m (BackendEvent backend field)
newEvent = (m (BackendEvent backend field) -> t m (BackendEvent backend field)
forall (m :: * -> *) a. Monad m => m a -> t m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift .) ((EventParams
    (RootSelector backend)
    field
    (EventReference (BackendEvent backend))
  -> m (BackendEvent backend field))
 -> EventParams
      (RootSelector backend)
      field
      (EventReference (BackendEvent backend))
 -> t m (BackendEvent backend field))
-> (backend
    -> EventParams
         (RootSelector backend)
         field
         (EventReference (BackendEvent backend))
    -> m (BackendEvent backend field))
-> backend
-> EventParams
     (RootSelector backend)
     field
     (EventReference (BackendEvent backend))
-> t m (BackendEvent backend field)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. backend
-> EventParams
     (RootSelector backend)
     field
     (EventReference (BackendEvent backend))
-> m (BackendEvent backend field)
forall field.
backend
-> EventParams
     (RootSelector backend)
     field
     (EventReference (BackendEvent backend))
-> m (BackendEvent backend field)
forall (m :: * -> *) backend field.
EventBackendIn m backend =>
backend
-> EventParams
     (RootSelector backend)
     field
     (EventReference (BackendEvent backend))
-> m (BackendEvent backend field)
newEvent
  newInstantEvent :: forall field.
backend
-> EventParams
     (RootSelector backend)
     field
     (EventReference (BackendEvent backend))
-> t m (EventReference (BackendEvent backend))
newInstantEvent = (m (EventReference (BackendEvent backend))
-> t m (EventReference (BackendEvent backend))
forall (m :: * -> *) a. Monad m => m a -> t m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift .) ((EventParams
    (RootSelector backend)
    field
    (EventReference (BackendEvent backend))
  -> m (EventReference (BackendEvent backend)))
 -> EventParams
      (RootSelector backend)
      field
      (EventReference (BackendEvent backend))
 -> t m (EventReference (BackendEvent backend)))
-> (backend
    -> EventParams
         (RootSelector backend)
         field
         (EventReference (BackendEvent backend))
    -> m (EventReference (BackendEvent backend)))
-> backend
-> EventParams
     (RootSelector backend)
     field
     (EventReference (BackendEvent backend))
-> t m (EventReference (BackendEvent backend))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. backend
-> EventParams
     (RootSelector backend)
     field
     (EventReference (BackendEvent backend))
-> m (EventReference (BackendEvent backend))
forall field.
backend
-> EventParams
     (RootSelector backend)
     field
     (EventReference (BackendEvent backend))
-> m (EventReference (BackendEvent backend))
forall (m :: * -> *) backend field.
EventBackendIn m backend =>
backend
-> EventParams
     (RootSelector backend)
     field
     (EventReference (BackendEvent backend))
-> m (EventReference (BackendEvent backend))
newInstantEvent

{- | A resource allowing instrumentation of code via [fields](Observe-Event.html#g:selectorAndField) of
a given type.

It must be an 'EventIn' some monad to be useful.
-}
class Event (event  Type  Type) where
  -- | The type of [references](Observe-Event.html#g:relationships) to an 'Event'.
  type EventReference event  Type

  -- | Get a [reference](Observe-Event.html#g:relationships) to this 'Event'
  reference  event field  EventReference event

{- | An 'Event' which can be used in a given @m@onad.

Laws:

  * @finalize x >> finalize y@ = @finalize x@
-}
class (Event event, Monad m, ParametricFunctor m)  EventIn m event where
  -- | End the 'Event', perhaps due to an exception.
  --
  -- It is implementation-specific whether 'addField' after
  -- 'finalize' has any effect (but it is not an error).
  --
  -- Implementations should ensure that subsequent 'finalize'ations
  -- are no-ops.
  finalize  event field  Maybe SomeException  m ()

  -- | Add a [field](Observe-Event.html#g:selectorAndField) to an 'Event'.
  addField  event field  field  m ()

-- | An 'EventBackend' that does nothing.
instance Event (Const ()) where
  type EventReference (Const ()) = ()
  reference :: forall field. Const () field -> EventReference (Const ())
reference Const () field
_ = ()

-- | An 'EventBackend' that does nothing.
instance (Monad m, ParametricFunctor m)  EventIn m (Const ()) where
  finalize :: forall field. Const () field -> Maybe SomeException -> m ()
finalize Const () field
_ Maybe SomeException
_ = () -> m ()
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
  addField :: forall field. Const () field -> field -> m ()
addField Const () field
_ field
_ = () -> m ()
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()

{- | Combine two 'EventBackend's.

All operations are performed sequentially, with no
exception safety between calls.
-}
instance (Event e1, Event e2)  Event (Product e1 e2) where
  type EventReference (Product e1 e2) = (EventReference e1, EventReference e2)
  reference :: forall field. Product e1 e2 field -> EventReference (Product e1 e2)
reference (Pair e1 field
e1 e2 field
e2) = (e1 field -> EventReference e1
forall field. e1 field -> EventReference e1
forall (event :: * -> *) field.
Event event =>
event field -> EventReference event
reference e1 field
e1, e2 field -> EventReference e2
forall field. e2 field -> EventReference e2
forall (event :: * -> *) field.
Event event =>
event field -> EventReference event
reference e2 field
e2)

{- | Combine two 'EventBackend's.

All operations are performed sequentially, with no
exception safety between calls.
-}
instance (EventIn m e1, EventIn m e2)  EventIn m (Product e1 e2) where
  finalize :: forall field. Product e1 e2 field -> Maybe SomeException -> m ()
finalize (Pair e1 field
e1 e2 field
e2) Maybe SomeException
err = e1 field -> Maybe SomeException -> m ()
forall field. e1 field -> Maybe SomeException -> m ()
forall (m :: * -> *) (event :: * -> *) field.
EventIn m event =>
event field -> Maybe SomeException -> m ()
finalize e1 field
e1 Maybe SomeException
err m () -> m () -> m ()
forall a b. m a -> m b -> m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> e2 field -> Maybe SomeException -> m ()
forall field. e2 field -> Maybe SomeException -> m ()
forall (m :: * -> *) (event :: * -> *) field.
EventIn m event =>
event field -> Maybe SomeException -> m ()
finalize e2 field
e2 Maybe SomeException
err
  addField :: forall field. Product e1 e2 field -> field -> m ()
addField (Pair e1 field
e1 e2 field
e2) field
f = e1 field -> field -> m ()
forall field. e1 field -> field -> m ()
forall (m :: * -> *) (event :: * -> *) field.
EventIn m event =>
event field -> field -> m ()
addField e1 field
e1 field
f m () -> m () -> m ()
forall a b. m a -> m b -> m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> e2 field -> field -> m ()
forall field. e2 field -> field -> m ()
forall (m :: * -> *) (event :: * -> *) field.
EventIn m event =>
event field -> field -> m ()
addField e2 field
e2 field
f

unwrapPairParams  EventParams selector field (r1, r2)  (EventParams selector field r1, EventParams selector field r2)
unwrapPairParams :: forall (selector :: * -> *) field r1 r2.
EventParams selector field (r1, r2)
-> (EventParams selector field r1, EventParams selector field r2)
unwrapPairParams EventParams selector field (r1, r2)
params =
  ( EventParams selector field (r1, r2)
params{parent = parent1, causes = causes1}
  , EventParams selector field (r1, r2)
params{parent = parent2, causes = causes2}
  )
 where
  (Maybe r1
parent1, Maybe r2
parent2) = Maybe (r1, r2) -> (Maybe r1, Maybe r2)
forall a b. Maybe (a, b) -> (Maybe a, Maybe b)
forall (m :: * -> *) a b. MonadZip m => m (a, b) -> (m a, m b)
munzip EventParams selector field (r1, r2)
params.parent
  ([r1]
causes1, [r2]
causes2) = [(r1, r2)] -> ([r1], [r2])
forall a b. [(a, b)] -> ([a], [b])
forall (m :: * -> *) a b. MonadZip m => m (a, b) -> (m a, m b)
munzip EventParams selector field (r1, r2)
params.causes

{- | Lift an 'Event' into a 'MonadTrans'formed @m@onad.

Note that this instance is [incoherent](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/instances.html#overlapping-instances),
so it can be overridden for your @event@ type if need be. This instance will still be used in monad-generic code, however.
-}
instance {-# INCOHERENT #-} (EventIn m event, ParametricMonadTrans t, MonadTransMonadConstraint t m)  EventIn (t m) event where
  finalize :: forall field. event field -> Maybe SomeException -> t m ()
finalize = (m () -> t m ()
forall (m :: * -> *) a. Monad m => m a -> t m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift .) ((Maybe SomeException -> m ()) -> Maybe SomeException -> t m ())
-> (event field -> Maybe SomeException -> m ())
-> event field
-> Maybe SomeException
-> t m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. event field -> Maybe SomeException -> m ()
forall field. event field -> Maybe SomeException -> m ()
forall (m :: * -> *) (event :: * -> *) field.
EventIn m event =>
event field -> Maybe SomeException -> m ()
finalize
  addField :: forall field. event field -> field -> t m ()
addField = (m () -> t m ()
forall (m :: * -> *) a. Monad m => m a -> t m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift .) ((field -> m ()) -> field -> t m ())
-> (event field -> field -> m ()) -> event field -> field -> t m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. event field -> field -> m ()
forall field. event field -> field -> m ()
forall (m :: * -> *) (event :: * -> *) field.
EventIn m event =>
event field -> field -> m ()
addField

-- * Selectors

{- | A nested sequence of selectors, starting from a
given root @selector@ family and ending in a selector
selecting a given @field@ type.

For example, given:

> data FooSelector :: Type -> Type where Foo :: FooSelector FooField
> data FooField
> type instance SubSelector FooField = BarSelector
> data BarSelector :: Type -> Type where Bar :: BarSelector BarField
> data BarField
> type instance SubSelector BarField = NoEventsSelector

Then @Leaf Foo@ is a sequence 'Selectors' picking out an 'Event' with field
type @FooField@, and @Foo :\/ Leaf Bar@ is a sequence of 'Selectors' picking out
an 'Event' with field type @BarField@ underneath an 'Event' with field type @FooField@.

See the [selector and field documentation](Observe-Event.html#g:selectorAndField) for more details.
-}
data Selectors selector field where
  Leaf  selector field  Selectors selector field
  (:/)  selector field  Selectors (SubSelector field) field'  Selectors selector field'

infixr 5 :/

{- | The [selector](Observe-Event.html#g:selectorAndField) type for sub-'Event's underneath
an 'Event' of the given @field@ type.

Instrumented code will typically involve nested scopes of events, including calls across
different modules, with different types of events expected in different contexts. To support
this, each field type has an associated 'SubSelector' type to identify the kind of events
that can occur in the scope where the event is active. This results in a tree of event
types represented by a tree of selectors, reflecting the tree of instrumented source
components: Each selector of the root selector type specifies a field type, which in turn
specifies yet another selector (and, with it, its sub-tree). Use cases which require picking
out a linear path through this tree can use 'Selectors'.

If there are no sub-'Event's under 'Event's with field type @f@, then you can use
 t'Observe.Event.NoEventsSelector': @type instance SubSelector f = NoEventsSelector@.

If you want to retain the set of possible event types as in the parent scope, simply set
'SubSelector' to the very same selector type that the parent selector came from.
-}
type family SubSelector field  Type  Type