multiwalk-0.3.0.1: test/Benchmark.hs
{-# LANGUAGE RankNTypes #-}
module Main where
import Commonmark.Pandoc
import Commonmark.Parser
import Control.DeepSeq
import Control.Exception (evaluate)
import qualified Control.Monad.Trans.Writer.Lazy as LW
import qualified Control.Monad.Trans.Writer.Strict as CPSW
import qualified Control.Monad.Trans.Writer.Strict as SW
import Control.MultiWalk
import qualified Data.ByteString as B
import Data.Functor (($>))
import Data.Functor.Compose (Compose (..))
import Data.List (sort)
import Data.Text (Text)
import Data.Text.Encoding (decodeUtf8)
import Test.Tasty.Bench
import Test.Tasty.HUnit
import Text.Pandoc.Builder (Blocks, toList)
import Text.Pandoc.Definition
import Text.Pandoc.Generic (queryWith)
import qualified Text.Pandoc.Walk as PW
data PTag
instance MultiTag PTag where
type
MultiTypes PTag =
'[ Block
, Inline
]
type DoubleList a = MatchWith [[a]] (Trav (Compose [] []) a)
instance MultiSub PTag Block where
type
SubTypes PTag Block =
'SpecList
'[ ToSpec (Trav [] Inline)
, ToSpec (DoubleList Inline)
, ToSpec (Trav [] Block)
, ToSpec (DoubleList Block)
, ToSpec
( Under
[([Inline], [[Block]])]
'NoSel
(Under ([Inline], [[Block]]) 'NoSel (Trav [] Inline))
)
, ToSpec
( Under
[([Inline], [[Block]])]
'NoSel
(Under ([Inline], [[Block]]) 'NoSel (DoubleList Block))
)
]
instance MultiSub PTag Inline where
type
SubTypes PTag Inline =
'SpecList '[ToSpec (Trav [] Inline), ToSpec (Trav [] Block)]
prepEnv :: IO [Block]
prepEnv = do
text <- decodeUtf8 <$> B.readFile "test/text.md"
Right (Cm b :: Cm () Blocks) <- pure $ commonmark "test/text.md" text
evaluate $ force $ toList b
multiLW :: [Block] -> [Text]
multiLW = foldMap (LW.execWriter . w)
where
w = buildMultiW @PTag $ \f list ->
let blks x@(CodeBlock _ c) = LW.tell [c] $> x
blks x = f x
inls x@(Code _ c) = LW.tell [c] $> x
inls x = f x
in list .> blks .> inls
multiSW :: [Block] -> [Text]
multiSW = foldMap (SW.execWriter . w)
where
w = buildMultiW @PTag $ \f list ->
let blks x@(CodeBlock _ c) = SW.tell [c] $> x
blks x = f x
inls x@(Code _ c) = SW.tell [c] $> x
inls x = f x
in list .> blks .> inls
multiCPSW :: [Block] -> [Text]
multiCPSW = foldMap (CPSW.execWriter . w)
where
w = buildMultiW @PTag $ \f list ->
let blks x@(CodeBlock _ c) = CPSW.tell [c] $> x
blks x = f x
inls x@(Code _ c) = CPSW.tell [c] $> x
inls x = f x
in list .> blks .> inls
multi :: [Block] -> [Text]
multi = foldMap $
buildMultiQ @PTag $ \sub list ->
list ?> blks sub ?> inls sub
where
blks :: Query PTag [Text] -> Block -> [Text]
blks _ (CodeBlock _ c) = [c]
blks f x = f x
inls :: Query PTag [Text] -> Inline -> [Text]
inls _ (Code _ c) = [c]
inls f x = f x
gene :: [Block] -> [Text]
gene x = queryWith blks x <> queryWith inls x
where
blks :: Block -> [Text]
blks (CodeBlock _ c) = [c]
blks _ = []
inls :: Inline -> [Text]
inls (Code _ c) = [c]
inls _ = []
wal :: [Block] -> [Text]
wal x = PW.query blks x <> PW.query inls x
where
blks :: Block -> [Text]
blks (CodeBlock _ c) = [c]
blks _ = []
inls :: Inline -> [Text]
inls (Code _ c) = [c]
inls _ = []
main :: IO ()
main =
defaultMain
[ bgroup
"query"
[ env prepEnv $ bench "multiwalk" . nf multi
, env prepEnv $ bench "mw lw" . nf multiLW
, env prepEnv $ bench "mw sw" . nf multiSW
, env prepEnv $ bench "mw cpsw" . nf multiCPSW
, env prepEnv $ bench "syb" . nf gene
, env prepEnv $ bench "pandoc.walk" . nf wal
, env prepEnv $ \blocks ->
-- The other implementations return out of order (!!!) fragments, but sorted they should be the same.
bgroup
"equality"
[ testCase "multiwalk eq syb" (sort (multi blocks) @?= sort (gene blocks))
, testCase "multiwalk eq pandoc.walk" (sort (multi blocks) @?= sort (wal blocks))
]
]
]