heftia-effects-0.7.0.0: bench/BenchLocal.hs
{-# LANGUAGE CPP #-}
-- SPDX-License-Identifier: BSD-3-Clause
-- (c) 2022 Xy Ren; 2024 Sayo contributors
-- Benchmarking higher-order effects #2: Local environments
module BenchLocal where
import Control.Carrier.Reader qualified as F
import Control.Monad.Hefty qualified as H
import Data.Effect.Reader qualified as H
import Effectful qualified as EL
import Effectful.Reader.Dynamic qualified as EL
import Polysemy qualified as P
import Polysemy.Reader qualified as P
import "data-effects" Control.Effect.Interpret qualified as HD
#ifdef VERSION_eff
import "eff" Control.Effect qualified as E
#endif
programHeftia :: (H.Ask Int `H.In` es, H.Local Int `H.In` es) => Int -> H.Eff es Int
programHeftia = \case
0 -> H.ask'_
n -> H.local'_ @Int (+ 1) (programHeftia (n - 1))
{-# NOINLINE programHeftia #-}
localHeftia :: Int -> Int
localHeftia n = HD.runPure $ H.runAsk @Int 0 $ H.runLocal @Int $ programHeftia n
localHeftiaDeep0, localHeftiaDeep1, localHeftiaDeep2, localHeftiaDeep3, localHeftiaDeep4, localHeftiaDeep5 :: Int -> Int
localHeftiaDeep0 n = HD.runPure $ hrun $ hrun $ hrun $ hrun $ hrun $ H.runAsk @Int 0 $ hrun $ hrun $ hrun $ hrun $ hrun $ H.runLocal @Int $ programHeftia n
localHeftiaDeep1 n = HD.runPure $ hrun $ hrun $ hrun $ hrun $ hrun $ H.runAsk @Int 0 $ hrun $ hrun $ hrun $ hrun $ H.runLocal @Int $ hrun $ programHeftia n
localHeftiaDeep2 n = HD.runPure $ hrun $ hrun $ hrun $ hrun $ hrun $ H.runAsk @Int 0 $ hrun $ hrun $ hrun $ H.runLocal @Int $ hrun $ hrun $ programHeftia n
localHeftiaDeep3 n = HD.runPure $ hrun $ hrun $ hrun $ hrun $ hrun $ H.runAsk @Int 0 $ hrun $ hrun $ H.runLocal @Int $ hrun $ hrun $ hrun $ programHeftia n
localHeftiaDeep4 n = HD.runPure $ hrun $ hrun $ hrun $ hrun $ hrun $ H.runAsk @Int 0 $ hrun $ H.runLocal @Int $ hrun $ hrun $ hrun $ hrun $ programHeftia n
localHeftiaDeep5 n = HD.runPure $ hrun $ hrun $ hrun $ hrun $ hrun $ H.runAsk @Int 0 $ H.runLocal @Int $ hrun $ hrun $ hrun $ hrun $ hrun $ programHeftia n
hrun :: H.Eff (H.Ask () ': es) a -> H.Eff es a
hrun = H.runAsk ()
programSem :: (P.Reader Int `P.Member` es) => Int -> P.Sem es Int
programSem = \case
0 -> P.ask
n -> P.local @Int (+ 1) (programSem (n - 1))
{-# NOINLINE programSem #-}
localSem :: Int -> Int
localSem n = P.run $ P.runReader @Int 0 $ programSem n
localSemDeep :: Int -> Int
localSemDeep n = P.run $ run $ run $ run $ run $ run $ P.runReader @Int 0 $ run $ run $ run $ run $ run $ programSem n
where
run = P.runReader ()
programFused :: (F.Has (F.Reader Int) sig m) => Int -> m Int
programFused = \case
0 -> F.ask
n -> F.local @Int (+ 1) (programFused (n - 1))
{-# NOINLINE programFused #-}
localFused :: Int -> Int
localFused n = F.run $ F.runReader @Int 0 $ programFused n
localFusedDeep :: Int -> Int
localFusedDeep n = F.run $ run $ run $ run $ run $ run $ F.runReader @Int 0 $ run $ run $ run $ run $ run $ programFused n
where
run = F.runReader ()
programEffectful :: (EL.Reader Int EL.:> es) => Int -> EL.Eff es Int
programEffectful = \case
0 -> EL.ask
n -> EL.local @Int (+ 1) (programEffectful (n - 1))
{-# NOINLINE programEffectful #-}
localEffectful :: Int -> Int
localEffectful n = EL.runPureEff $ EL.runReader @Int 0 $ programEffectful n
localEffectfulDeep :: Int -> Int
localEffectfulDeep n =
EL.runPureEff $ run $ run $ run $ run $ run $ EL.runReader @Int 0 $ run $ run $ run $ run $ run $ programEffectful n
where
run = EL.runReader ()
#ifdef VERSION_eff
programEff :: (E.Reader Int E.:< es) => Int -> E.Eff es Int
programEff = \case
0 -> E.ask
n -> E.local @Int (+ 1) (programEff (n - 1))
{-# NOINLINE programEff #-}
localEff :: Int -> Int
localEff n = E.run $ E.runReader @Int 0 $ programEff n
localEffDeep :: Int -> Int
localEffDeep n = E.run $ run $ run $ run $ run $ run $ E.runReader @Int 0 $ run $ run $ run $ run $ run $ programEff n
where
run = E.runReader ()
#endif
{-
The MTL case is disabled because of conflicting functional dependencies.
When using something other than Reader to build up the stack, it is considered
that the performance degradation caused by the pure stack factor cannot be
measured.
programMtl :: (M.MonadReader Int m) => Int -> m Int
programMtl = \case
0 -> M.ask
n -> M.local (+ 1) (programMtl (n - 1))
{-# NOINLINE programMtl #-}
localMtl :: Int -> Int
localMtl n = M.runReader 0 $ programMtl n
localMtlDeep :: Int -> Int
localMtlDeep n = M.runIdentity $ run $ run $ run $ run $ run $ M.runReader 0 $ run $ run $ run $ run $ run $ programMtl n
where
run = (`M.runReaderT` ())
-}