{-# LANGUAGE
  DataKinds,
  GADTs,
  KindSignatures,
  RankNTypes,
  ScopedTypeVariables,
  TypeOperators #-}
-- | = Reader as an algebraic effect
--
-- Access to a read-only environment.
module Bluefin.Algae.Reader
  ( -- * Operation
    Reader(..)
  , ask

    -- * Handler
  , runReader
  ) where

import Data.Kind (Type)
import Bluefin.Algae
import Bluefin.Eff (Eff, type (:>), type (:&))

-- | The reader effect.
data Reader (a :: Type) :: AEffect where
  -- | Ask for a value.
  Ask :: Reader a a

-- | Ask for a value. Call the 'Ask' operation.
ask :: s :> ss => Handler (Reader a) s -> Eff ss a
ask :: forall (s :: Effects) (ss :: Effects) a.
(s :> ss) =>
Handler (Reader a) s -> Eff ss a
ask Handler (Reader a) s
h = Handler (Reader a) s -> Reader a a -> Eff ss a
forall (s :: Effects) (ss :: Effects) (f :: AEffect) a.
(s :> ss) =>
Handler f s -> f a -> Eff ss a
call Handler (Reader a) s
h Reader a a
forall a. Reader a a
Ask

-- | Answer 'Ask' operations of the handled computation with a fixed value.
runReader :: forall a b ss.
  a -> (forall s. Handler (Reader a) s -> Eff (s :& ss) b) -> Eff ss b
runReader :: forall a b (ss :: Effects).
a
-> (forall (s :: Effects). Handler (Reader a) s -> Eff (s :& ss) b)
-> Eff ss b
runReader a
a = HandlerBody (Reader a) ss b
-> (forall (s :: Effects). Handler (Reader a) s -> Eff (s :& ss) b)
-> Eff ss b
forall (f :: AEffect) (ss :: Effects) a.
HandlerBody f ss a -> ScopedEff f ss a -> Eff ss a
handle Reader a x -> (x -> Eff ss b) -> Eff ss b
HandlerBody (Reader a) ss b
readerHandler
  where
    readerHandler :: Reader a r -> (r -> Eff ss b) -> Eff ss b
    readerHandler :: HandlerBody (Reader a) ss b
readerHandler Reader a r
Ask r -> Eff ss b
k = r -> Eff ss b
k a
r
a