packages feed

yaftee-basic-monads-0.1.0.0: src/Control/Monad/Yaftee/Reader.hs

{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE ScopedTypeVariables, TypeApplications #-}
{-# LANGUAGE RequiredTypeArguments #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures, TypeOperators #-}
{-# LANGUAGE FlexibleContexts #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

module Control.Monad.Yaftee.Reader (

	-- * NORMAL

	R, ask, local, run,

	-- * NAMED

	Named, askN, localN, runN

	) where

import GHC.TypeLits
import Control.Monad.Yaftee.Eff qualified as Eff
import Control.Monad.HigherFreer qualified as F
import Control.HigherOpenUnion qualified as Union
import Data.Kind
import Data.Functor.Identity
import Data.HigherFunctor qualified as HFunctor
import Data.FTCQueue qualified as Q

-- * NORMAL

type R e = Named "" e

ask :: Union.Member (R e) effs => Eff.E effs i o e
ask = askN ""

local :: forall e effs i o a . Union.Member (R e) effs =>
	(e -> e) -> Eff.E effs i o a -> Eff.E effs i o a
local = localN ""

run :: forall e effs i o a . HFunctor.Loose (Union.U effs) =>
	Eff.E (R e ': effs) i o a -> e -> Eff.E effs  i o a
run = runN

-- * NAMED

data Named (nm :: Symbol) e (f :: Type -> Type -> Type -> Type) i o a where
	Ask :: forall nm e f i o . Named nm e f i o e
	Local :: forall nm e f i o a . (e -> e) -> f i o a -> Named nm e f i o a

askN :: forall nm -> Union.Member (Named nm e) effs => Eff.E effs i o e
askN nm = Eff.effh (Ask @nm)

localN :: forall nm -> Union.Member (Named nm e) effs =>
	(e -> e) -> Eff.E effs i o a -> Eff.E effs i o a
localN nm = (Eff.effh .) . Local @nm

runN :: forall nm e effs i o a . HFunctor.Loose (Union.U effs) =>
	Eff.E (Named nm e ': effs) i o a -> e -> Eff.E effs i o a
m `runN` e = case m of
	F.Pure x -> F.Pure x
	u F.:>>= q -> case Union.decomp u of
		Left u' -> HFunctor.map ((Identity <$>) . (`runN` e)) Identity u' F.:>>=
			Q.singleton (((`runN` e) F.. q) . runIdentity)
		Right Ask -> (q F.$ e) `runN` e
		Right (Local f a) ->  (`runN` e) F.. q =<< a `runN` f e