machines 0.6.3 → 0.6.4
raw patch · 10 files changed
+426/−113 lines, 10 filesdep +streamingdep −conduit-combinatorsdep ~basedep ~conduitdep ~containers
Dependencies added: streaming
Dependencies removed: conduit-combinators
Dependency ranges changed: base, conduit, containers
Files
- .gitignore +13/−2
- .travis.yml +135/−88
- CHANGELOG.markdown +8/−0
- benchmarks/Benchmarks.hs +214/−11
- examples/Examples.hs +3/−0
- examples/machines-examples.cabal +14/−2
- machines.cabal +17/−10
- src/Data/Machine/Mealy.hs +7/−0
- src/Data/Machine/MealyT.hs +13/−0
- src/Data/Machine/Type.hs +2/−0
.gitignore view
@@ -12,10 +12,21 @@ *.hi *~ *#-.cabal-sandbox+.stack-work/+cabal-dev+*.chi+*.chs.h+*.dyn_o+*.dyn_hi+.hpc+.hsenv+.cabal-sandbox/ cabal.sandbox.config *.prof *.aux *.hp *.eventlog-.stack-work/+cabal.project.local+cabal.project.local~+.HTF/+.ghc.environment.*
.travis.yml view
@@ -1,115 +1,162 @@-# This file has been generated -- see https://github.com/hvr/multi-ghc-travis+# This Travis job script has been generated by a script via+#+# runghc make_travis_yml_2.hs '-o' '.travis.yml' '--ghc-head' '--irc-channel=irc.freenode.org#haskell-lens' '--no-no-tests-no-bench' '--no-unconstrained' 'cabal.project'+#+# For more information, see https://github.com/hvr/multi-ghc-travis+# language: c sudo: false +git:+ submodules: false # whether to recursively clone submodules++notifications:+ irc:+ channels:+ - "irc.freenode.org#haskell-lens"+ skip_join: true+ template:+ - "\x0313machines\x03/\x0306%{branch}\x03 \x0314%{commit}\x03 %{build_url} %{message}"+ cache: directories:- - $HOME/.cabsnap - $HOME/.cabal/packages+ - $HOME/.cabal/store before_cache: - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log- - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.tar+ # remove files that are regenerated by 'cabal update'+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.*+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/*.json+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.cache+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar.idx + - rm -rfv $HOME/.cabal/packages/head.hackage+ matrix: include:- - env: CABALVER=1.24 GHCVER=7.4.2- compiler: ": #GHC 7.4.2"- addons: {apt: {packages: [cabal-install-1.24,ghc-7.4.2], sources: [hvr-ghc]}}- - env: CABALVER=1.24 GHCVER=7.6.3- compiler: ": #GHC 7.6.3"- addons: {apt: {packages: [cabal-install-1.24,ghc-7.6.3], sources: [hvr-ghc]}}- - env: CABALVER=1.24 GHCVER=7.8.4- compiler: ": #GHC 7.8.4"- addons: {apt: {packages: [cabal-install-1.24,ghc-7.8.4], sources: [hvr-ghc]}}- - env: CABALVER=1.24 GHCVER=7.10.3- compiler: ": #GHC 7.10.3"- addons: {apt: {packages: [cabal-install-1.24,ghc-7.10.3], sources: [hvr-ghc]}}- - env: CABALVER=1.24 GHCVER=8.0.2- compiler: ": #GHC 8.0.2"- addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.2], sources: [hvr-ghc]}}- - env: CABALVER=2.0 GHCVER=8.2.1- compiler: ": #GHC 8.2.1"- addons: {apt: {packages: [cabal-install-2.0,ghc-8.2.1], sources: [hvr-ghc]}}- - env: CABALVER=head GHCVER=head- compiler: ": #GHC head"- addons: {apt: {packages: [cabal-install-head,ghc-head], sources: [hvr-ghc]}}+ - compiler: "ghc-8.6.1"+ env: GHCHEAD=true+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.6.1], sources: [hvr-ghc]}}+ - compiler: "ghc-8.4.3"+ # env: TEST=--disable-tests BENCH=--disable-benchmarks+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.4.3], sources: [hvr-ghc]}}+ - compiler: "ghc-8.2.2"+ # env: TEST=--disable-tests BENCH=--disable-benchmarks+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.2.2], sources: [hvr-ghc]}}+ - compiler: "ghc-8.0.2"+ # env: TEST=--disable-tests BENCH=--disable-benchmarks+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.0.2], sources: [hvr-ghc]}}+ - compiler: "ghc-7.10.3"+ # env: TEST=--disable-tests BENCH=--disable-benchmarks+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.10.3], sources: [hvr-ghc]}}+ - compiler: "ghc-7.8.4"+ # env: TEST=--disable-tests BENCH=--disable-benchmarks+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.4], sources: [hvr-ghc]}}+ - compiler: "ghc-7.6.3"+ # env: TEST=--disable-tests BENCH=--disable-benchmarks+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.6.3], sources: [hvr-ghc]}}+ - compiler: "ghc-7.4.2"+ # env: TEST=--disable-tests BENCH=--disable-benchmarks+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.4.2], sources: [hvr-ghc]}}+ - compiler: "ghc-head"+ env: GHCHEAD=true+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-head], sources: [hvr-ghc]}} allow_failures:- - env: CABALVER=head GHCVER=head+ - compiler: "ghc-head"+ - compiler: "ghc-8.6.1" before_install:- - unset CC- - export PATH=$HOME/.cabal/bin:/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH+ - HC=${CC}+ - HCVER=${HC/ghc-/}+ - HCPKG=${HC/ghc/ghc-pkg}+ - unset CC+ - ROOTDIR=$(pwd)+ - mkdir -p $HOME/.local/bin+ - "PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$HOME/local/bin:$PATH"+ - HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\1 * 10000 + \2 * 100 + \3/') ))+ - echo $HCNUMVER install:- - cabal --version- - echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"- - if [ -f $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz ];- then- zcat $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz >- $HOME/.cabal/packages/hackage.haskell.org/00-index.tar;- fi- - travis_retry cabal update -v- - sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config- - cabal install --only-dependencies --enable-tests --dry -v > installplan.txt- - sed -i -e '1,/^Resolving /d' installplan.txt; cat installplan.txt--# check whether current requested install-plan matches cached package-db snapshot- - if diff -u installplan.txt $HOME/.cabsnap/installplan.txt;- then- echo "cabal build-cache HIT";- rm -rfv .ghc;- cp -a $HOME/.cabsnap/ghc $HOME/.ghc;- cp -a $HOME/.cabsnap/lib $HOME/.cabsnap/share $HOME/.cabsnap/bin $HOME/.cabal/;- else- echo "cabal build-cache MISS";- rm -rf $HOME/.cabsnap;- mkdir -p $HOME/.ghc $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin;- cabal install -j --only-dependencies --enable-tests;- fi+ - cabal --version+ - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"+ - |+ if dpkg --compare-versions "${HCVER}" ge "8.0"; then+ BENCH=${BENCH---enable-benchmarks}+ else+ BENCH=${BENCH---disable-benchmarks}+ fi+ - TEST=${TEST---enable-tests}+ - HADDOCK=${HADDOCK-true}+ - UNCONSTRAINED=${UNCONSTRAINED-true}+ - NOINSTALLEDCONSTRAINTS=${NOINSTALLEDCONSTRAINTS-false}+ - GHCHEAD=${GHCHEAD-false}+ - travis_retry cabal update -v+ - "sed -i.bak 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config"+ - rm -fv cabal.project cabal.project.local+ # Overlay Hackage Package Index for GHC HEAD: https://github.com/hvr/head.hackage+ - |+ if $GHCHEAD; then+ sed -i 's/-- allow-newer: .*/allow-newer: *:base/' ${HOME}/.cabal/config+ for pkg in $($HCPKG list --simple-output); do pkg=$(echo $pkg | sed 's/-[^-]*$//'); sed -i "s/allow-newer: /allow-newer: *:$pkg, /" ${HOME}/.cabal/config; done -# snapshot package-db on cache miss- - if [ ! -d $HOME/.cabsnap ];- then- echo "snapshotting package-db to build-cache";- mkdir $HOME/.cabsnap;- cp -a $HOME/.ghc $HOME/.cabsnap/ghc;- cp -a $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin installplan.txt $HOME/.cabsnap/;- fi+ echo 'repository head.hackage' >> ${HOME}/.cabal/config+ echo ' url: http://head.hackage.haskell.org/' >> ${HOME}/.cabal/config+ echo ' secure: True' >> ${HOME}/.cabal/config+ echo ' root-keys: 07c59cb65787dedfaef5bd5f987ceb5f7e5ebf88b904bbd4c5cbdeb2ff71b740' >> ${HOME}/.cabal/config+ echo ' 2e8555dde16ebd8df076f1a8ef13b8f14c66bad8eafefd7d9e37d0ed711821fb' >> ${HOME}/.cabal/config+ echo ' 8f79fd2389ab2967354407ec852cbe73f2e8635793ac446d09461ffb99527f6e' >> ${HOME}/.cabal/config+ echo ' key-threshold: 3' >> ${HOME}/.cabal.config -# Here starts the actual work to be performed for the package under-# test; any command which exits with a non-zero exit code causes the-# build to fail.-script:- # -v2 provides useful information for debugging- - cabal configure --enable-tests -v2+ grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$' - # this builds all libraries and executables- # (including tests/benchmarks)- - cabal build+ cabal new-update head.hackage -v+ fi+ - grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'+ - "printf 'packages: \".\" \"./examples\"\\n' > cabal.project"+ - touch cabal.project.local+ - "if ! $NOINSTALLEDCONSTRAINTS; then for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/^/constraints: /' | sed 's/-[^-]*$/ installed/' >> cabal.project.local; done; fi"+ - cat cabal.project || true+ - cat cabal.project.local || true+ - if [ -f "./configure.ac" ]; then+ (cd "." && autoreconf -i);+ fi+ - if [ -f "./examples/configure.ac" ]; then+ (cd "./examples" && autoreconf -i);+ fi+ - rm -f cabal.project.freeze+ - cabal new-build -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project" --dep -j2 all+ - rm -rf .ghc.environment.* "."/dist "./examples"/dist+ - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX) - - cabal test+# Here starts the actual work to be performed for the package under test;+# any command which exits with a non-zero exit code causes the build to fail.+script:+ # test that source-distributions can be generated+ - (cd "." && cabal sdist)+ - (cd "./examples" && cabal sdist)+ - mv "."/dist/machines-*.tar.gz "./examples"/dist/machines-examples-*.tar.gz ${DISTDIR}/+ - cd ${DISTDIR} || false+ - find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \;+ - "printf 'packages: machines-*/*.cabal machines-examples-*/*.cabal\\n' > cabal.project"+ - touch cabal.project.local+ - "if ! $NOINSTALLEDCONSTRAINTS; then for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/^/constraints: /' | sed 's/-[^-]*$/ installed/' >> cabal.project.local; done; fi"+ - cat cabal.project || true+ - cat cabal.project.local || true - # tests that a source-distribution can be generated- - cabal sdist+ # build & run tests, build benchmarks+ - cabal new-build -w ${HC} ${TEST} ${BENCH} all+ - if [ "x$TEST" = "x--enable-tests" ]; then cabal new-test -w ${HC} ${TEST} ${BENCH} all; fi - # check that the generated source-distribution can be built & installed- - export SRC_TGZ=$(cabal info . | awk '{print $2 ".tar.gz";exit}') ;- cd dist/;- if [ -f "$SRC_TGZ" ]; then- cabal install --force-reinstalls "$SRC_TGZ";- else- echo "expected '$SRC_TGZ' not found";- exit 1;- fi+ # cabal check+ - (cd machines-* && cabal check)+ - (cd machines-examples-* && cabal check) -notifications:- irc:- channels:- - "irc.freenode.org#haskell-lens"- skip_join: true- template:- - "\x0313machines\x03/\x0306%{branch}\x03 \x0314%{commit}\x03 %{build_url} %{message}"+ # haddock+ - rm -rf ./dist-newstyle+ - if $HADDOCK; then cabal new-haddock -w ${HC} ${TEST} ${BENCH} all; else echo "Skipping haddock generation";fi +# REGENDATA ["-o",".travis.yml","--ghc-head","--irc-channel=irc.freenode.org#haskell-lens","--no-no-tests-no-bench","--no-unconstrained","cabal.project"] # EOF
CHANGELOG.markdown view
@@ -1,3 +1,11 @@+0.6.4 [2018.07.03]+------------------+* Add `Semigroup` and `Monoid` instances for `Mealy` and `MealyT`.+* Mark `runT` and `runT_` as `INLINEABLE`.+* Increase the scope of the benchmarks. Also include the `streaming` library+ among the things that are benchmarked.+* Allow building with `containers-0.6`.+ 0.6.3 ----- * Add `Semigroup` instance for `Is`
benchmarks/Benchmarks.hs view
@@ -1,15 +1,18 @@ module Main (main) where import Control.Applicative+import Data.Function ((&)) import Control.Monad (void) import Control.Monad.Identity import Criterion.Main+import Data.Void import qualified Data.Conduit as C import qualified Data.Conduit.Combinators as CC import qualified Data.Conduit.List as C import qualified Data.Machine as M import qualified Pipes as P import qualified Pipes.Prelude as P+import qualified Streaming.Prelude as S import Prelude value :: Int@@ -18,85 +21,285 @@ drainM :: M.ProcessT Identity Int o -> () drainM m = runIdentity $ M.runT_ (sourceM M.~> m) +drainMIO :: M.ProcessT IO Int o -> IO ()+drainMIO m = M.runT_ (sourceM M.~> m)+ drainP :: P.Proxy () Int () a Identity () -> () drainP p = runIdentity $ P.runEffect $ P.for (sourceP P.>-> p) P.discard -drainC :: C.Conduit Int Identity a -> ()-drainC c = runIdentity $ (sourceC C.$= c) C.$$ C.sinkNull+drainPIO :: P.Proxy () Int () a IO () -> IO ()+drainPIO p = P.runEffect $ sourceP P.>-> p P.>-> P.mapM_ (\_ -> return ()) -drainSC :: C.Sink Int Identity b -> ()-drainSC c = runIdentity $ void $! sourceC C.$$ c+drainC :: C.ConduitT Int a Identity () -> ()+drainC c = runIdentity $ C.runConduit $ (sourceC C..| c) C..| C.sinkNull +drainCIO :: C.ConduitT Int a IO () -> IO ()+drainCIO c = C.runConduit $ (sourceC C..| c) C..| C.mapM_ (\_ -> return ())++drainSC :: C.ConduitT Int Void Identity b -> ()+drainSC c = runIdentity $ void $! C.runConduit $ sourceC C..| c++drainS :: (S.Stream (S.Of Int) Identity () -> S.Stream (S.Of Int) Identity ())+ -> ()+drainS s = runIdentity $ S.effects $ sourceS & s++drainSIO :: (S.Stream (S.Of Int) IO () -> S.Stream (S.Of Int) IO ()) -> IO ()+drainSIO s = sourceS & s & S.mapM_ (\_ -> return ())++sourceM :: M.Source Int sourceM = M.enumerateFromTo 1 value++sourceC :: Monad m => C.ConduitT i Int m () sourceC = C.enumFromTo 1 value++sourceP :: Monad m => P.Producer' Int m () sourceP = P.each [1..value] +sourceS :: Monad m => S.Stream (S.Of Int) m ()+sourceS = S.each [1..value]+ main :: IO () main = defaultMain [ bgroup "map" [ bench "machines" $ whnf drainM (M.mapping (+1))+ , bench "streaming" $ whnf drainS (S.map (+1)) , bench "pipes" $ whnf drainP (P.map (+1)) , bench "conduit" $ whnf drainC (C.map (+1)) ] , bgroup "drop" [ bench "machines" $ whnf drainM (M.dropping value)+ , bench "streaming" $ whnf drainS (S.drop value) , bench "pipes" $ whnf drainP (P.drop value) , bench "conduit" $ whnf drainC (C.drop value) ] , bgroup "dropWhile" [ bench "machines" $ whnf drainM (M.droppingWhile (<= value))+ , bench "streaming" $ whnf drainS (S.dropWhile (<= value)) , bench "pipes" $ whnf drainP (P.dropWhile (<= value)) , bench "conduit" $ whnf drainC (CC.dropWhile (<= value)) ] , bgroup "scan" [ bench "machines" $ whnf drainM (M.scan (+) 0)+ , bench "streaming" $ whnf drainS (S.scan (+) 0 id) , bench "pipes" $ whnf drainP (P.scan (+) 0 id) , bench "conduit" $ whnf drainC (CC.scanl (+) 0) ] , bgroup "take" [ bench "machines" $ whnf drainM (M.taking value)+ , bench "streaming" $ whnf drainS (S.take value) , bench "pipes" $ whnf drainP (P.take value) , bench "conduit" $ whnf drainC (C.isolate value) ] , bgroup "takeWhile" [ bench "machines" $ whnf drainM (M.takingWhile (<= value))+ , bench "streaming" $ whnf drainS (S.takeWhile (<= value)) , bench "pipes" $ whnf drainP (P.takeWhile (<= value)) , bench "conduit" $ whnf drainC (CC.takeWhile (<= value)) ] , bgroup "fold" [ bench "machines" $ whnf drainM (M.fold (+) 0)- , bench "pipes" $ whnf (P.fold (+) 0 id) sourceP+ , bench "streaming" $ whnf runIdentity $ (S.fold (+) 0 id) sourceS+ , bench "pipes" $ whnf runIdentity $ (P.fold (+) 0 id) sourceP , bench "conduit" $ whnf drainSC (C.fold (+) 0) ] , bgroup "filter" [ bench "machines" $ whnf drainM (M.filtered even)+ , bench "streaming" $ whnf drainS (S.filter even) , bench "pipes" $ whnf drainP (P.filter even) , bench "conduit" $ whnf drainC (C.filter even) ] , bgroup "mapM" [ bench "machines" $ whnf drainM (M.autoM Identity)+ , bench "streaming" $ whnf drainS (S.mapM Identity) , bench "pipes" $ whnf drainP (P.mapM Identity) , bench "conduit" $ whnf drainC (C.mapM Identity) ] , bgroup "zip" [ bench "machines" $ whnf (\x -> runIdentity $ M.runT_ x) (M.capT sourceM sourceM M.zipping)+ , bench "streaming" $ whnf (\x -> runIdentity $ S.effects $ x)+ (S.zip sourceS sourceS) , bench "pipes" $ whnf (\x -> runIdentity $ P.runEffect $ P.for x P.discard) (P.zip sourceP sourceP)- , bench "conduit" $ whnf (\x -> runIdentity $ x C.$$ C.sinkNull)+ , bench "conduit" $ whnf (\x -> runIdentity $ C.runConduit $ x C..| C.sinkNull) (C.getZipSource $ (,) <$> C.ZipSource sourceC <*> C.ZipSource sourceC) ]+ , bgroup "concat"+ [ bench "machines" $ whnf drainM (M.mapping (replicate 10) M.~> M.asParts)+ , bench "streaming" $ whnf drainS (S.concat . S.map (replicate 10))+ , bench "pipes" $ whnf drainP (P.map (replicate 10) P.>-> P.concat)+ , bench "conduit" $ whnf drainC (C.map (replicate 10) C..| C.concat)+ ] , bgroup "last" [ bench "machines" $ whnf drainM (M.final)- , bench "pipes" $ whnf P.last sourceP+ , bench "streaming" $ whnf runIdentity $ S.last sourceS+ , bench "pipes" $ whnf runIdentity $ P.last sourceP ] , bgroup "buffered" [ bench "machines" $ whnf drainM (M.buffered 1000) ]- , bgroup "concat"- [ bench "machines" $ whnf drainM (M.mapping (replicate 10) M.~> M.asParts)- , bench "pipes" $ whnf drainP (P.map (replicate 10) P.>-> P.concat)- , bench "conduit" $ whnf drainC (C.map (replicate 10) C.$= C.concat)+ , bgroup "toList"+ [ bench "machines" $ whnf (length . runIdentity) $ M.runT sourceM+ , bench "streaming" $ whnf (length . runIdentity)+ $ S.toList sourceS >>= (\(xs S.:> _) -> return xs)+ , bench "pipes" $ whnf (length . runIdentity) $ P.toListM sourceP+ , bench "conduit" $ whnf (length . runIdentity)+ $ C.runConduit $ sourceC C..| CC.sinkList+ ]+ , bgroup "toListIO"+ [ bench "machines" $ whnfIO $ M.runT sourceM+ , bench "streaming" $ whnfIO $ S.toList sourceS+ , bench "pipes" $ whnfIO $ P.toListM sourceP+ , bench "conduit" $ whnfIO $ C.runConduit $ sourceC C..| CC.sinkList+ ]++ , bgroup "compose"+ [+ -- Compose multiple ops, all stages letting everything through+ let m = M.filtered (<= value)+ s = S.filter (<= value)+ p = P.filter (<= value)+ c = C.filter (<= value)+ in bgroup "summary"+ [ bench "machines" $ whnf drainM $ m M.~> m M.~> m M.~> m+ , bench "streaming" $ whnf drainS $ \x -> s x & s & s & s+ , bench "pipes" $ whnf drainP $ p P.>-> p P.>-> p P.>-> p+ , bench "conduit" $ whnf drainC $ c C..| c C..| c C..| c+ ]++ -- IO monad makes a big difference especially for machines+ , let m = M.filtered (<= value)+ s = S.filter (<= value)+ p = P.filter (<= value)+ c = C.filter (<= value)+ in bgroup "summary-io"+ [ bench "machines" $ whnfIO $ drainMIO $ m M.~> m M.~> m M.~> m+ , bench "streaming" $ whnfIO $ drainSIO $ \x -> s x & s & s & s+ , bench "pipes" $ whnfIO $ drainPIO $ p P.>-> p P.>-> p P.>-> p+ , bench "conduit" $ whnfIO $ drainCIO $ c C..| c C..| c C..| c+ ]++ -- Scaling with same operation in sequence+ , let f = M.filtered (<= value)+ in bgroup "machines"+ [ bench "1-filter" $ whnf drainM f+ , bench "2-filters" $ whnf drainM $ f M.~> f+ , bench "3-filters" $ whnf drainM $ f M.~> f M.~> f+ , bench "4-filters" $ whnf drainM $ f M.~> f M.~> f M.~> f+ ]+ , let f = S.filter (<= value)+ in bgroup "streaming"+ [ bench "1-filter" $ whnf drainS (\x -> f x)+ , bench "2-filters" $ whnf drainS $ \x -> f x & f+ , bench "3-filters" $ whnf drainS $ \x -> f x & f & f+ , bench "4-filters" $ whnf drainS $ \x -> f x & f & f & f+ ]+ , let f = P.filter (<= value)+ in bgroup "pipes"+ [ bench "1-filter" $ whnf drainP f+ , bench "2-filters" $ whnf drainP $ f P.>-> f+ , bench "3-filters" $ whnf drainP $ f P.>-> f P.>-> f+ , bench "4-filters" $ whnf drainP $ f P.>-> f P.>-> f P.>-> f+ ]+ , let f = C.filter (<= value)+ in bgroup "conduit"+ [ bench "1-filter" $ whnf drainC f+ , bench "2-filters" $ whnf drainC $ f C..| f+ , bench "3-filters" $ whnf drainC $ f C..| f C..| f+ , bench "4-filters" $ whnf drainC $ f C..| f C..| f C..| f+ ]++ , let m = M.mapping (subtract 1) M.~> M.filtered (<= value)+ s = S.filter (<= value) . S.map (subtract 1)+ p = P.map (subtract 1) P.>-> P.filter (<= value)+ c = C.map (subtract 1) C..| C.filter (<= value)+ in bgroup "summary-alternate"+ [ bench "machines" $ whnf drainM $ m M.~> m M.~> m M.~> m+ , bench "streaming" $ whnf drainS $ \x -> s x & s & s & s+ , bench "pipes" $ whnf drainP $ p P.>-> p P.>-> p P.>-> p+ , bench "conduit" $ whnf drainC $ c C..| c C..| c C..| c+ ]++ , let f = M.mapping (subtract 1) M.~> M.filtered (<= value)+ in bgroup "machines-alternate"+ [ bench "1-map-filter" $ whnf drainM f+ , bench "2-map-filters" $ whnf drainM $ f M.~> f+ , bench "3-map-filters" $ whnf drainM $ f M.~> f M.~> f+ , bench "4-map-filters" $ whnf drainM $ f M.~> f M.~> f M.~> f+ ]+ , let f = S.filter (<= value) . S.map (subtract 1)+ in bgroup "streaming-alternate"+ [ bench "1-map-filter" $ whnf drainS (\x -> f x)+ , bench "2-map-filters" $ whnf drainS $ \x -> f x & f+ , bench "3-map-filters" $ whnf drainS $ \x -> f x & f & f+ , bench "4-map-filters" $ whnf drainS $ \x -> f x & f & f & f+ ]+ , let f = P.map (subtract 1) P.>-> P.filter (<= value)+ in bgroup "pipes-alternate"+ [ bench "1-map-filter" $ whnf drainP f+ , bench "2-map-filters" $ whnf drainP $ f P.>-> f+ , bench "3-map-filters" $ whnf drainP $ f P.>-> f P.>-> f+ , bench "4-map-filters" $ whnf drainP $ f P.>-> f P.>-> f P.>-> f+ ]+ , let f = C.map (subtract 1) C..| C.filter (<= value)+ in bgroup "conduit-alternate"+ [ bench "1-map-filter" $ whnf drainC f+ , bench "2-map-filters" $ whnf drainC $ f C..| f+ , bench "3-map-filters" $ whnf drainC $ f C..| f C..| f+ , bench "4-map-filters" $ whnf drainC $ f C..| f C..| f C..| f+ ]++ -- how filtering affects the subsequent composition+ , let m = M.filtered (> value)+ s = S.filter (> value)+ p = P.filter (> value)+ c = C.filter (> value)+ in bgroup "summary-filter-effect"+ [ bench "machines" $ whnf drainM $ m M.~> m M.~> m M.~> m+ , bench "streaming" $ whnf drainS $ \x -> s x & s & s & s+ , bench "pipes" $ whnf drainP $ p P.>-> p P.>-> p P.>-> p+ , bench "conduit" $ whnf drainC $ c C..| c C..| c C..| c+ ]++ , let m = M.filtered (> value)+ s = S.filter (> value)+ p = P.filter (> value)+ c = C.filter (> value)+ in bgroup "summary-filter-effect-io"+ [ bench "machines" $ whnfIO $ drainMIO $ m M.~> m M.~> m M.~> m+ , bench "streaming" $ whnfIO $ drainSIO $ \x -> s x & s & s & s+ , bench "pipes" $ whnfIO $ drainPIO $ p P.>-> p P.>-> p P.>-> p+ , bench "conduit" $ whnfIO $ drainCIO $ c C..| c C..| c C..| c+ ]++ , let f = M.filtered (> value)+ in bgroup "machines-filter-effect"+ [ bench "filter1" $ whnf drainM f+ , bench "filter2" $ whnf drainM $ f M.~> f+ , bench "filter3" $ whnf drainM $ f M.~> f M.~> f+ , bench "filter4" $ whnf drainM $ f M.~> f M.~> f M.~> f+ ]+ , let f = S.filter (> value)+ in bgroup "streaming-filter-effect"+ [ bench "filter1" $ whnf drainS (\x -> f x)+ , bench "filter2" $ whnf drainS $ \x -> f x & f+ , bench "filter3" $ whnf drainS $ \x -> f x & f & f+ , bench "filter4" $ whnf drainS $ \x -> f x & f & f & f+ ]+ , let f = P.filter (> value)+ in bgroup "pipes-filter-effect"+ [ bench "filter1" $ whnf drainP f+ , bench "filter2" $ whnf drainP $ f P.>-> f+ , bench "filter3" $ whnf drainP $ f P.>-> f P.>-> f+ , bench "filter4" $ whnf drainP $ f P.>-> f P.>-> f P.>-> f+ ]+ , let f = C.filter (> value)+ in bgroup "conduit-filter-effect"+ [ bench "filter1" $ whnf drainC f+ , bench "filter2" $ whnf drainC $ f C..| f+ , bench "filter3" $ whnf drainC $ f C..| f C..| f+ , bench "filter4" $ whnf drainC $ f C..| f C..| f C..| f+ ] ] ]
examples/Examples.hs view
@@ -1,8 +1,11 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE RankNTypes #-} module Examples where +#if !(MIN_VERSION_base(4,8,0)) import Control.Applicative+#endif import Control.Exception import Control.Monad.Trans import Data.Machine
examples/machines-examples.cabal view
@@ -11,10 +11,19 @@ bug-reports: http://github.com/ekmett/machines/issues copyright: Copyright (C) 2014 Edward A. Kmett synopsis: Networked stream transducers-description: machines examples+description: Networked stream transducers+ .+ @machines@ examples build-type: Simple-tested-with: GHC == 7.4.1+tested-with: GHC == 7.4.2+ , GHC == 7.6.3+ , GHC == 7.8.4+ , GHC == 7.10.3+ , GHC == 8.0.2+ , GHC == 8.2.2+ , GHC == 8.4.3+ , GHC == 8.6.1 source-repository head type: git@@ -28,3 +37,6 @@ exposed-modules: Examples++ default-language: Haskell2010+ ghc-options: -Wall
machines.cabal view
@@ -1,6 +1,6 @@ name: machines category: Control, Enumerator-version: 0.6.3+version: 0.6.4 license: BSD3 cabal-version: >= 1.10 license-file: LICENSE@@ -17,7 +17,14 @@ Rúnar Bjarnason's talk on machines can be downloaded from: <https://dl.dropbox.com/u/4588997/Machines.pdf> build-type: Custom-tested-with: GHC == 7.4.2, GHC == 7.6.3, GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.2, GHC == 8.2.1+tested-with: GHC == 7.4.2+ , GHC == 7.6.3+ , GHC == 7.8.4+ , GHC == 7.10.3+ , GHC == 8.0.2+ , GHC == 8.2.2+ , GHC == 8.4.3+ , GHC == 8.6.1 extra-source-files: .travis.yml .gitignore@@ -45,8 +52,8 @@ adjunctions >= 4.2 && < 5, base >= 4.5 && < 5, comonad >= 3 && < 6,- containers >= 0.3 && < 0.6,- distributive < 0.6,+ containers >= 0.3 && < 0.7,+ distributive < 0.7, pointed >= 3 && < 6, profunctors >= 3 && < 6, semigroupoids >= 5 && < 6,@@ -100,7 +107,7 @@ default-language: Haskell2010 build-depends: base == 4.*,- doctest >= 0.11.1 && < 0.13,+ doctest >= 0.11.1 && < 0.17, machines ghc-options: -Wall -threaded hs-source-dirs: tests@@ -113,10 +120,10 @@ ghc-options: -O2 -rtsopts -threaded build-depends:- base == 4.*,- conduit >= 1.0 && < 1.3,- conduit-combinators >= 0.2.5 && < 1.2,- criterion >= 0.6 && < 1.3,+ base >= 4.9 && < 5,+ conduit >= 1.3 && < 1.4,+ criterion >= 0.6 && < 1.6, machines, mtl >= 2 && < 2.3,- pipes >= 4 && < 4.4+ pipes >= 4 && < 4.4,+ streaming >= 0.1.4 && < 0.3
src/Data/Machine/Mealy.hs view
@@ -225,3 +225,10 @@ instance Closed Mealy where closed m = cotabulate $ \fs x -> cosieve m (fmap ($x) fs)++instance Semigroup b => Semigroup (Mealy a b) where+ f <> g = Mealy $ \x -> runMealy f x <> runMealy g x++instance Monoid b => Monoid (Mealy a b) where+ mempty = Mealy mempty+ mappend f g = Mealy $ \x -> runMealy f x `mappend` runMealy g x
src/Data/Machine/MealyT.hs view
@@ -28,6 +28,7 @@ import Control.Monad.Trans import Control.Monad.Identity import Data.Profunctor+import Data.Semigroup import qualified Control.Category as C import Prelude @@ -132,3 +133,15 @@ instance AutomatonM MealyT where autoT = autoMealyTImpl +instance (Semigroup b, Monad m) => Semigroup (MealyT m a b) where+ f <> g = MealyT $ \x -> do+ (fx, f') <- runMealyT f x+ (gx, g') <- runMealyT g x+ return (fx <> gx, f' <> g')++instance (Monoid b, Monad m) => Monoid (MealyT m a b) where+ mempty = MealyT $ \_ -> return mempty+ mappend f g = MealyT $ \x -> do+ (fx, f') <- runMealyT f x+ (gx, g') <- runMealyT g x+ return (fx `mappend` gx, f' `mappend` g')
src/Data/Machine/Type.hs view
@@ -164,6 +164,7 @@ -} -- | Stop feeding input into model, taking only the effects.+{-# INLINABLE runT_ #-} runT_ :: Monad m => MachineT m k b -> m () runT_ m = runMachineT m >>= \v -> case v of Stop -> return ()@@ -171,6 +172,7 @@ Await _ _ e -> runT_ e -- | Stop feeding input into model and extract an answer+{-# INLINABLE runT #-} runT :: Monad m => MachineT m k b -> m [b] runT (MachineT m) = m >>= \v -> case v of Stop -> return []