Я сделал некоторые критерии Criterion, чтобы оценить, какую производительность я потеряю, запустив мой код поверх стека монады. Результаты были довольно любопытными, и я, вероятно, наткнулся на ловушку лени в своем тесте.
Тест показывает, что запуск WriterT String IO
выполняется в 20 раз (!) медленнее, чем запуск простой IO
, даже если не используется tell
. Странно, если я складываю WriterT
с ReaderT
и ContT
, он всего лишь в 5 раз медленнее. Вероятно, это ошибка в моем тесте. Что я здесь делаю неправильно?
Тест
{-#LANGUAGE BangPatterns#-}
module Main where
import Criterion.Main
import Control.Monad
import Control.Monad.Writer
import Control.Monad.Reader
import Control.Monad.Cont
process :: Monad m => Int -> m Int
process = foldl (>=>) return (replicate 100000 (\(!x) -> return (x+1)))
test n = process n >> return ()
main = defaultMain [
bench "Plain" t0
,bench "Writer" t1
,bench "Reader" t2
,bench "Cont" t3
,bench "RWC" t4
]
t0 = test 1 :: IO ()
t1 = (runWriterT (test 1:: WriterT String IO ()) >> return ()) :: IO ()
t2 = (runReaderT (test 1:: ReaderT String IO ()) "" >> return ()) :: IO ()
t3 = (runContT (test 1:: ContT () IO ()) (return) >> return ()) :: IO ()
t4 = ((runWriterT . flip runReaderT "" . flip runContT return $
(test 1 :: ContT () (ReaderT String (WriterT String IO)) ())) >> return ()) :: IO ()
Результаты
benchmarking Plain mean: 1.938814 ms, lb 1.846508 ms, ub 2.052165 ms, ci 0.950 std dev: 519.7248 us, lb 428.4684 us, ub 709.3670 us, ci 0.950 benchmarking Writer mean: 39.50431 ms, lb 38.25233 ms, ub 40.74437 ms, ci 0.950 std dev: 6.378220 ms, lb 5.738682 ms, ub 7.155760 ms, ci 0.950 benchmarking Reader mean: 12.52823 ms, lb 12.03947 ms, ub 13.09994 ms, ci 0.950 std dev: 2.706265 ms, lb 2.324519 ms, ub 3.462641 ms, ci 0.950 benchmarking Cont mean: 8.100272 ms, lb 7.634488 ms, ub 8.633348 ms, ci 0.950 std dev: 2.562829 ms, lb 2.281561 ms, ub 2.878463 ms, ci 0.950 benchmarking RWC mean: 9.871992 ms, lb 9.436721 ms, ub 10.37302 ms, ci 0.950 std dev: 2.387364 ms, lb 2.136819 ms, ub 2.721750 ms, ci 0.950