content: {-# LANGUAGE TypeApplications #-}
  module Bench.Reader
  ( benchmark
  ) where
  
  import Control.Carrier.Reader
  import Control.Monad (replicateM_)
  import Control.Monad.Trans.Reader (runReaderT)
  import Test.Tasty.Bench
  
  benchmark :: Benchmark
  benchmark = bgroup "Reader"
    [ bgroup "ask"
      [ bench "(->)"    $ whnf (`asking` 'c') n
      , bgroup "Identity"
        [ bench "ReaderC" $ whnf (run . runReader 'c' . asking) n
        , bench "ReaderT" $ whnf (run . (`runReaderT` 'c') . asking) n
        ]
      , bgroup "IO"
        [ bench "ReaderC" $ whnfAppIO (runReader 'c' . asking) n
        , bench "ReaderT" $ whnfAppIO ((`runReaderT` 'c') . asking) n
        ]
      ]
    , bgroup "local"
      [ bench "(->)"    $ whnf (`locally` 'c') n
      , bgroup "Identity"
        [ bench "ReaderC" $ whnf (run . runReader 'c' . locally) n
        , bench "ReaderT" $ whnf (run . (`runReaderT` 'c') . locally) n
        ]
      , bgroup "IO"
        [ bench "ReaderC" $ whnfAppIO (runReader 'c' . locally) n
        , bench "ReaderT" $ whnfAppIO ((`runReaderT` 'c') . locally) n
        ]
      ]
    ]
    where
    n = 100000
  
  asking :: Has (Reader Char) sig m => Int -> m ()
  asking i = replicateM_ i (ask @Char)
  {-# INLINE asking #-}
  
  locally :: Has (Reader Char) sig m => Int -> m ()
  locally i = replicateM_ i (local @Char succ (ask @Char))
  {-# INLINE locally #-}
  