{-# LANGUAGE RankNTypes #-} module Main (main) where import Criterion.Main import Common (commonMain) import Control.Monad.Identity (Identity, runIdentity) import Pipes import qualified Pipes.Prelude as P import Prelude hiding (enumFromTo) defaultMax :: Int defaultMax = 10000 main :: IO () main = commonMain defaultMax preludeBenchmarks enumFromTo :: (Int -> a) -> Int -> Int -> Producer a Identity () enumFromTo f n1 n2 = loop n1 where loop n = if n <= n2 then do yield $! f n loop $! n + 1 else return () {-# INLINABLE enumFromTo #-} drain :: Producer b Identity r -> r drain p = runIdentity $ runEffect $ for p discard msum :: (Monad m) => Producer Int m () -> m Int msum = P.foldM (\a b -> return $ a + b) (return 0) return scanMSum :: (Monad m) => Pipe Int Int m r scanMSum = P.scanM (\x y -> return (x + y)) (return 0) return -- Using runIdentity seems to reduce outlier counts. preludeBenchmarks :: Int -> [Benchmark] preludeBenchmarks vmax = let applyBench b = b benchEnum_p benchEnum_p = enumFromTo id 1 vmax in [ bgroup "Folds" $ map applyBench [ bench "all" . whnf (runIdentity . P.all (<= vmax)) , bench "any" . whnf (runIdentity . P.any (> vmax)) , bench "find" . whnf (runIdentity . P.find (== vmax)) , bench "findIndex" . whnf (runIdentity . P.findIndex (== vmax)) , bench "fold" . whnf (runIdentity . P.fold (+) 0 id) , bench "foldM" . whnf (runIdentity . msum) , bench "head" . nf (runIdentity . P.head) , bench "index" . nf (runIdentity . P.index (vmax-1)) , bench "last" . nf (runIdentity . P.last) , bench "length" . whnf (runIdentity . P.length) , bench "null" . whnf (runIdentity . P.null) , bench "toList" . nf P.toList ] , bgroup "Pipes" $ map applyBench [ bench "chain" . whnf (drain . (>-> P.chain (\_ -> return ()))) , bench "drop" . whnf (drain . (>-> P.drop vmax)) , bench "dropWhile" . whnf (drain . (>-> P.dropWhile (<= vmax))) , bench "filter" . whnf (drain . (>-> P.filter even)) , bench "findIndices" . whnf (drain . (>-> P.findIndices (<= vmax))) , bench "map" . whnf (drain . (>-> P.map id)) , bench "mapM" . whnf (drain . (>-> P.mapM return)) , bench "take" . whnf (drain . (>-> P.take vmax)) , bench "takeWhile" . whnf (drain . (>-> P.takeWhile (<= vmax))) , bench "scan" . whnf (drain . (>-> P.scan (+) 0 id)) , bench "scanM" . whnf (drain . (>-> scanMSum)) ] ++ [ bench "concat" $ whnf (drain . (>-> P.concat)) $ enumFromTo Just 1 vmax ] , bgroup "Zips" $ map applyBench [ bench "zip" . whnf (drain . P.zip benchEnum_p) , bench "zipWith" . whnf (drain . P.zipWith (+) benchEnum_p) ] , bgroup "enumFromTo.vs.each" [ bench "enumFromTo" $ whnf (drain . enumFromTo id 1) vmax , bench "each" $ whnf (drain . each) [1..vmax] ] ]