packages feed

capability-0.4.0.0: src/Capability/Source/Internal/Class.hs

-- | Defines a capability for computations that consume a stream of values
-- as part of their execution.
--
-- Programs comsuming streams of data are common. Examples: rolling up input
-- events. Sources are similar to Python generators.
--
-- This can be thought of as a reader capability where there's no guarantee that
-- one reads the same value each time.
--
-- The 'HasSource' capability enables separating the logic responsible for
-- emitting events from that responsible for collecting or handling them.
-- The name is because a source is needed to produce the locally consumed stream.
--

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeInType #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE UndecidableInstances #-}

{-# OPTIONS_HADDOCK hide #-}

module Capability.Source.Internal.Class where

import Capability.Reflection
import Data.Coerce (coerce)
import Data.Kind (Type)
import GHC.Exts (Proxy#, proxy#)

-- | Sourcing capability.
--
-- An instance does not need to fulfill any additional laws
-- besides the monad laws.
class Monad m
  => HasSource (tag :: k) (a :: Type) (m :: Type -> Type) | tag m -> a
  where
    -- | For technical reasons, this method needs an extra proxy argument.
    -- You only need it if you are defining new instances of 'HasSource'.
    -- Otherwise, you will want to use 'await'.
    -- See 'await' for more documentation.
    await_ :: Proxy# tag -> m a

-- | @await \@tag a@
-- takes @a@ from the source capability @tag@.
await :: forall tag a m. HasSource tag a m => m a
await = await_ (proxy# @tag)
{-# INLINE await #-}

-- | @awaits \@tag@
-- retrieves the image by @f@ of the environment
-- of the reader capability @tag@.
--
-- prop> awaits @tag f = f <$> await @tag
awaits :: forall tag r m a. HasSource tag r m => (r -> a) -> m a
awaits f = f <$> await @tag
{-# INLINE awaits #-}

--------------------------------------------------------------------------------

data instance Reified tag (HasSource tag a) m = ReifiedSource {_await :: m a}

instance
  ( Monad m,
    Reifies s (Reified tag (HasSource tag a) m)
  ) =>
  HasSource tag a (Reflected s (HasSource tag a) m)
  where
  await_ _ = coerce $ _await (reified @s)
  {-# INLINE await_ #-}