packages feed

effectful-0.0.0.0: bench/Countdown.hs

{-# LANGUAGE CPP #-}
module Countdown where

import Data.Functor.Identity

-- eff
#ifdef VERSION_eff
import qualified Control.Effect as L
#endif

-- effectful
import qualified Effectful as E
import qualified Effectful.Reader as E
import qualified Effectful.State as E
import qualified Effectful.State.MVar as ME
import qualified Effectful.State.Dynamic as DE

-- freer-simple
#ifdef VERSION_freer_simple
import qualified Control.Monad.Freer as FS
import qualified Control.Monad.Freer.Reader as FS
import qualified Control.Monad.Freer.State as FS
#endif

-- fused-effects
#ifdef VERSION_fused_effects
import qualified Control.Algebra as FE
import qualified Control.Carrier.Reader as FE
import qualified Control.Carrier.State.Strict as FE
#endif

-- mtl
import qualified Control.Monad.Reader as M
import qualified Control.Monad.State as M

-- polysemy
#ifdef VERSION_polysemy
import qualified Polysemy as P
import qualified Polysemy.Reader as P
import qualified Polysemy.State as P
#endif

----------------------------------------
-- reference

countdownRef :: Integer -> (Integer, Integer)
countdownRef n = if n <= 0 then (n, n) else countdownRef $ n - 1
{-# NOINLINE countdownRef #-}

----------------------------------------
-- mtl

programMtl :: M.MonadState Integer m => m Integer
programMtl = do
  n <- M.get @Integer
  if n <= 0
    then pure n
    else do
      M.put (n - 1)
      programMtl
{-# NOINLINE programMtl #-}

countdownMtl :: Integer -> (Integer, Integer)
countdownMtl n = flip M.runState n $ programMtl

countdownMtlDeep :: Integer -> (Integer, Integer)
countdownMtlDeep n = runIdentity
  . runR . runR . runR . runR . runR . runR . runR . runR . runR . runR
  . flip M.runStateT n
  . runR . runR . runR . runR . runR . runR . runR . runR . runR . runR
  $ programMtl
  where
    runR = flip M.runReaderT ()

----------------------------------------
-- effectful (pure)

programEffectfulStatic :: E.State Integer E.:> es => E.Eff es Integer
programEffectfulStatic = do
  n <- E.get @Integer
  if n <= 0
    then pure n
    else do
      E.put (n - 1)
      programEffectfulStatic
{-# NOINLINE programEffectfulStatic #-}

countdownEffectfulStatic :: Integer -> IO (Integer, Integer)
countdownEffectfulStatic n = E.runEff . E.runState n $ programEffectfulStatic

countdownEffectfulStaticDeep :: Integer -> IO (Integer, Integer)
countdownEffectfulStaticDeep n = E.runEff
  . runR . runR . runR . runR . runR . runR . runR . runR . runR . runR
  . E.runState n
  . runR . runR . runR . runR . runR . runR . runR . runR . runR . runR
  $ programEffectfulStatic
  where
    runR = E.runReader ()

----------------------------------------
-- effectful (mvar)

programEffectfulMVar :: ME.State Integer E.:> es => E.Eff es Integer
programEffectfulMVar = do
  n <- ME.get @Integer
  if n <= 0
    then pure n
    else do
      ME.put (n - 1)
      programEffectfulMVar
{-# NOINLINE programEffectfulMVar #-}

countdownEffectfulMVar :: Integer -> IO (Integer, Integer)
countdownEffectfulMVar n = E.runEff . ME.runState n $ programEffectfulMVar

countdownEffectfulMVarDeep :: Integer -> IO (Integer, Integer)
countdownEffectfulMVarDeep n = E.runEff
  . runR . runR . runR . runR . runR . runR . runR . runR . runR . runR
  . ME.runState n
  . runR . runR . runR . runR . runR . runR . runR . runR . runR . runR
  $ programEffectfulMVar
  where
    runR = E.runReader ()

----------------------------------------
-- effectful (dynamic)

programEffectfulDynamic :: DE.State Integer E.:> es => E.Eff es Integer
programEffectfulDynamic = do
  n <- DE.get @Integer
  if n <= 0
    then pure n
    else do
      DE.put (n - 1)
      programEffectfulDynamic
{-# NOINLINE programEffectfulDynamic #-}

countdownEffectfulDynPure :: Integer -> IO (Integer, Integer)
countdownEffectfulDynPure n = E.runEff . DE.runState n $ programEffectfulDynamic

countdownEffectfulDynMVar :: Integer -> IO (Integer, Integer)
countdownEffectfulDynMVar n = E.runEff . DE.runStateMVar n $ programEffectfulDynamic

countdownEffectfulDynPureDeep :: Integer -> IO (Integer, Integer)
countdownEffectfulDynPureDeep n = E.runEff
  . runR . runR . runR . runR . runR . runR . runR . runR . runR . runR
  . DE.runState n
  . runR . runR . runR . runR . runR . runR . runR . runR . runR . runR
  $ programEffectfulDynamic
  where
    runR = E.runReader ()

countdownEffectfulDynMVarDeep :: Integer -> IO (Integer, Integer)
countdownEffectfulDynMVarDeep n = E.runEff
  . runR . runR . runR . runR . runR . runR . runR . runR . runR . runR
  . DE.runStateMVar n
  . runR . runR . runR . runR . runR . runR . runR . runR . runR . runR
  $ programEffectfulDynamic
  where
    runR = E.runReader ()

----------------------------------------
-- fused-effects

#ifdef VERSION_fused_effects

programFusedEffects :: FE.Has (FE.State Integer) sig m => m Integer
programFusedEffects = do
  n <- FE.get @Integer
  if n <= 0
    then pure n
    else do
      FE.put (n - 1)
      programFusedEffects
{-# NOINLINE programFusedEffects #-}

countdownFusedEffects :: Integer -> (Integer, Integer)
countdownFusedEffects n = FE.run . FE.runState n $ programFusedEffects

countdownFusedEffectsDeep :: Integer -> (Integer, Integer)
countdownFusedEffectsDeep n = FE.run
  . runR . runR . runR . runR . runR . runR . runR . runR . runR . runR
  . FE.runState n
  . runR . runR . runR . runR . runR . runR . runR . runR . runR . runR
  $ programFusedEffects
  where
    runR = FE.runReader ()

#endif

----------------------------------------
-- polysemy

#ifdef VERSION_polysemy

programPolysemy :: P.Member (P.State Integer) r => P.Sem r Integer
programPolysemy = do
  n <- P.get @Integer
  if n <= 0
    then pure n
    else do
      P.put (n - 1)
      programPolysemy
{-# NOINLINE programPolysemy #-}

countdownPolysemy :: Integer -> (Integer, Integer)
countdownPolysemy n = P.run . P.runState n $ programPolysemy

countdownPolysemyDeep :: Integer -> (Integer, Integer)
countdownPolysemyDeep n = P.run
  . runR . runR . runR . runR . runR . runR . runR . runR . runR . runR
  . P.runState n
  . runR . runR . runR . runR . runR . runR . runR . runR . runR . runR
  $ programPolysemy
  where
    runR = P.runReader ()

#endif

----------------------------------------
-- eff

#ifdef VERSION_eff

programEff :: L.State Integer L.:< es => L.Eff es Integer
programEff = do
  n <- L.get @Integer
  if n <= 0
    then pure n
    else do
      L.put (n - 1)
      programEff
{-# NOINLINE programEff #-}

countdownEff :: Integer -> (Integer, Integer)
countdownEff n = L.run . L.runState n $ programEff

countdownEffDeep :: Integer -> (Integer, Integer)
countdownEffDeep n = L.run
  . runR . runR . runR . runR . runR . runR . runR . runR . runR . runR
  . L.runState n
  . runR . runR . runR . runR . runR . runR . runR . runR . runR . runR
  $ programEff
  where
    runR = L.runReader ()

#endif

----------------------------------------
-- freer-simple

#ifdef VERSION_freer_simple

programFreerSimple :: FS.Member (FS.State Integer) es => FS.Eff es Integer
programFreerSimple = do
  n <- FS.get @Integer
  if n <= 0
    then pure n
    else do
      FS.put (n - 1)
      programFreerSimple
{-# NOINLINE programFreerSimple #-}

countdownFreerSimple :: Integer -> (Integer, Integer)
countdownFreerSimple n = FS.run . FS.runState n $ programFreerSimple

countdownFreerSimpleDeep :: Integer -> (Integer, Integer)
countdownFreerSimpleDeep n = FS.run
  . runR . runR . runR . runR . runR . runR . runR . runR . runR . runR
  . FS.runState n
  . runR . runR . runR . runR . runR . runR . runR . runR . runR . runR
  $ programFreerSimple
  where
    runR = FS.runReader ()

#endif