packages feed

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

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

module Control.Monad.Yaftee.Writer (

	-- * NORMAL
	
	W, tell, run,

	-- * NAMED

	Named, tellN, runN

	) where

import GHC.TypeLits
import Control.Arrow
import Control.Monad.Yaftee.Eff qualified as Eff
import Control.HigherOpenUnion qualified as Union
import Data.HigherFunctor qualified as HFunctor

-- * NORMAL

type W w = Named "" w

tell :: Union.Member (W w) effs => w -> Eff.E effs i o ()
tell = tellN ""

run :: (Monoid w, HFunctor.Loose (Union.U effs)) =>
	Eff.E (W w ': effs) i o a -> Eff.E effs i o (a, w)
run = runN

-- * NAMED

type Named nm w = Union.FromFirst (Named_ nm w)
data Named_ (nm :: Symbol) w a where TellN :: forall nm w . w -> Named_ nm w ()

tellN :: forall nm -> Union.Member (Named nm w) effs => w -> Eff.E effs i o ()
tellN nm = Eff.eff . TellN @nm

runN :: forall nm w effs i o a . (Monoid w, HFunctor.Loose (Union.U effs)) =>
	Eff.E (Named nm w ': effs) i o a -> Eff.E effs i o (a, w)
runN = (uncurry (flip (,)) <$>)
	. Eff.handleRelay (mempty ,) snd \(TellN w) k -> ((w <>) `first`) <$> k ()