diff --git a/.cirrus.yml b/.cirrus.yml deleted file mode 100644 index 8790f21485..0000000000 --- a/.cirrus.yml +++ /dev/null @@ -1,106 +0,0 @@ -freebsd_instance: - image_family: freebsd-14-3 - -task: - name: FreeBSD+ghc-9.14.1+cabal - env: - PACKCHECK_COMMAND: cabal - - # ------------------------------------------------------------------------ - # Common options - # ------------------------------------------------------------------------ - CABAL_REINIT_CONFIG: y - LC_ALL: C.UTF-8 - - # ------------------------------------------------------------------------ - # What to build - # ------------------------------------------------------------------------ - # DISABLE_TEST: "y" - DISABLE_BENCH: "y" - DISABLE_DOCS: "y" - DISABLE_SDIST_BUILD: "y" - # DISABLE_SDIST_GIT_CHECK: "y" - DISABLE_DIST_CHECKS: "y" - - # ------------------------------------------------------------------------ - # Selecting tool versions - # ------------------------------------------------------------------------ - # For updating see: https://downloads.haskell.org/~ghcup/ - GHCUP_VERSION: 0.1.50.2 - GHCVER: 9.14.1 - - # ------------------------------------------------------------------------ - # stack options (if using stack builds) - # ------------------------------------------------------------------------ - # Note requiring a specific version of stack using STACKVER may fail due to - # github API limit while checking and upgrading/downgrading to the specific - # version. - #STACKVER: "1.6.5" - #STACK_UPGRADE: "y" - #STACK_YAML: "stack.yaml" - - # ------------------------------------------------------------------------ - # cabal options - # ------------------------------------------------------------------------ - CABAL_CHECK_RELAX: y - CABAL_PROJECT: cabal.project - - # ------------------------------------------------------------------------ - # Location of packcheck.sh (the shell script invoked to perform CI tests ). - # ------------------------------------------------------------------------ - # You can either commit the packcheck.sh script at this path in your repo or - # you can use it by specifying the PACKCHECK_REPO_URL option below in which - # case it will be automatically copied from the packcheck repo to this path - # during CI tests. In any case it is finally invoked from this path. - PACKCHECK: "./packcheck.sh" - # If you have not committed packcheck.sh in your repo at PACKCHECK - # then it is automatically pulled from this URL. - PACKCHECK_GITHUB_URL: "https://raw.githubusercontent.com/composewell/packcheck" - PACKCHECK_GITHUB_COMMIT: "b3743510c7c26f83254ffd9ef91bcd71560cff05" - - cabal_cache: - folder: ~/.cabal - fingerprint_script: echo $GHCVER - - # Cabal store is in .local/state/cabal - local_cache: - folder: ~/.local - fingerprint_script: echo $GHCVER - - ghcup_cache: - folder: ~/.ghcup - fingerprint_script: echo $GHCUP_VERSION $GHCVER - - #local_bin_cache: - # folder: ~/.local/bin - # fingerprint_script: echo $HLINT_VERSION - - # git is required for cabal files with git URLs - deps_install_script: | - pkg update - pkg install -y gmake - pkg install -y bash - pkg install -y git - - packcheck_install_script: | - if test ! -e "$PACKCHECK" - then - if test -z "$PACKCHECK_GITHUB_COMMIT" - then - die "PACKCHECK_GITHUB_COMMIT is not specified." - fi - PACKCHECK_URL=${PACKCHECK_GITHUB_URL}/${PACKCHECK_GITHUB_COMMIT}/packcheck.sh - curl --fail -sL -o "$PACKCHECK" $PACKCHECK_URL || exit 1 - chmod +x $PACKCHECK - elif test ! -x "$PACKCHECK" - then - chmod +x $PACKCHECK - fi - - packcheck_run_script: | - # Commands like mount, sysctl for info require sbin - # PTH=/usr/local/bin:/usr/bin:/bin:/sbin:/usr/sbin - # Use "bash -c" instead of invoking directly to preserve quoted - # arguments in PACKCHECK_COMMAND e.g. DOCSPEC_OPTIONS="--timeout 60". - # Direct invocation would word-split on spaces inside quoted values. - bash -c "$PACKCHECK $PACKCHECK_COMMAND" diff --git a/.github/workflows/freebsd.yml b/.github/workflows/freebsd.yml new file mode 100644 index 0000000000..b901119a6c --- /dev/null +++ b/.github/workflows/freebsd.yml @@ -0,0 +1,89 @@ +# FreeBSD CI +# +# FreeBSD is not a native GitHub Actions runner, so this workflow runs +# the build inside a VM via vmactions/freebsd-vm. It is kept separate +# from haskell.yml because the cache/restore step model in that +# workflow (hackage index, ghcup, deps caches) does not apply inside +# the VM. + +name: FREEBSD + +on: + workflow_dispatch: + pull_request: + push: + branches: + - master + +jobs: + build: + name: >- + freebsd-${{ matrix.release }} + ${{ matrix.command }} + ${{ matrix.ghc_version }} + runs-on: ubuntu-latest + continue-on-error: ${{ matrix.ignore_error }} + strategy: + fail-fast: false + matrix: + include: + - release: "14.3" + command: cabal + ghc_version: 9.14.1 + ignore_error: true + + steps: + - uses: actions/checkout@v4 + + - name: Build on FreeBSD + uses: vmactions/freebsd-vm@v1 + env: + PACKCHECK_COMMAND: ${{ matrix.command }} + GHCVER: ${{ matrix.ghc_version }} + # For updating see: https://downloads.haskell.org/~ghcup/ + GHCUP_VERSION: 0.1.50.2 + LC_ALL: C.UTF-8 + CABAL_REINIT_CONFIG: y + CABAL_CHECK_RELAX: y + CABAL_PROJECT: cabal.project + DISABLE_BENCH: "y" + DISABLE_DOCS: "y" + DISABLE_SDIST_BUILD: "y" + DISABLE_DIST_CHECKS: "y" + PACKCHECK: "./packcheck.sh" + PACKCHECK_GITHUB_URL: "https://raw.githubusercontent.com/composewell/packcheck" + PACKCHECK_GITHUB_COMMIT: "b3743510c7c26f83254ffd9ef91bcd71560cff05" + with: + release: ${{ matrix.release }} + usesh: true + copyback: false + envs: >- + PACKCHECK_COMMAND GHCVER GHCUP_VERSION LC_ALL + CABAL_REINIT_CONFIG CABAL_CHECK_RELAX CABAL_PROJECT + DISABLE_BENCH DISABLE_DOCS DISABLE_SDIST_BUILD DISABLE_DIST_CHECKS + PACKCHECK PACKCHECK_GITHUB_URL PACKCHECK_GITHUB_COMMIT + prepare: | + pkg update + pkg install -y gmake + pkg install -y bash + pkg install -y git + pkg install -y gmp + run: | + if test ! -e "$PACKCHECK" + then + if test -z "$PACKCHECK_GITHUB_COMMIT" + then + echo "PACKCHECK_GITHUB_COMMIT is not specified." >&2 + exit 1 + fi + PACKCHECK_URL=${PACKCHECK_GITHUB_URL}/${PACKCHECK_GITHUB_COMMIT}/packcheck.sh + curl --fail -sL -o "$PACKCHECK" $PACKCHECK_URL || exit 1 + chmod +x $PACKCHECK + elif test ! -x "$PACKCHECK" + then + chmod +x $PACKCHECK + fi + # Use "bash -c" instead of invoking directly to preserve quoted + # arguments in PACKCHECK_COMMAND e.g. DOCSPEC_OPTIONS="--timeout 60". + # Direct invocation would word-split on spaces inside quoted values. + bash -c "$PACKCHECK $PACKCHECK_COMMAND" diff --git a/.hlint.yaml b/.hlint.yaml index 4e5ca270de..a7633e77a9 100644 --- a/.hlint.yaml +++ b/.hlint.yaml @@ -48,6 +48,7 @@ [ --cpp-include=src , --cpp-include=src/Streamly/Internal/Data/Stream , --cpp-include=core/src/Streamly/Internal/Data/Array + , --cpp-include=core/src/doctest , --cpp-include=test , --cpp-define=CABAL_OS_LINUX , --cpp-define=linux_HOST_OS diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs b/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs index 8af6a8200d..11ee4658e4 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Expand.hs @@ -334,14 +334,14 @@ inspect $ 'unfoldEach `hasNoType` ''SPEC {-# INLINE unfoldEach2 #-} unfoldEach2 :: Int -> Int -> Int -> IO () unfoldEach2 outer inner start = drain $ - S.unfoldEach (UF.carry (sourceUnfoldrMUnfold inner start)) + S.unfoldEach (UF.carryInput (sourceUnfoldrMUnfold inner start)) $ sourceUnfoldrM outer start {-# INLINE unfoldEach3 #-} unfoldEach3 :: Int -> Int -> IO () unfoldEach3 linearCount start = drain $ do - S.unfoldEach (UF.carry (UF.lmap snd (sourceUnfoldrMUnfold nestedCount3 start))) - $ S.unfoldEach (UF.carry (sourceUnfoldrMUnfold nestedCount3 start)) + S.unfoldEach (UF.carryInput (UF.lmap snd (sourceUnfoldrMUnfold nestedCount3 start))) + $ S.unfoldEach (UF.carryInput (sourceUnfoldrMUnfold nestedCount3 start)) $ sourceUnfoldrM nestedCount3 start where @@ -732,28 +732,28 @@ fairUnfoldCrossEqn input = unfoldEachEqn :: Monad m => Unfold m ((), ()) Int -> Stream m Int -> m () unfoldEachEqn input ints = - let intu = Unfold.carry $ Unfold.lmap (const (undefined, undefined)) input + let intu = Unfold.carryInput $ Unfold.lmap (const (undefined, undefined)) input in result $ Stream.mapM checkPair $ Stream.unfoldEach intu ints fairUnfoldEachEqn :: Monad m => Unfold m ((), ()) Int -> Stream m Int -> m () fairUnfoldEachEqn input ints = - let intu = Unfold.carry $ Unfold.lmap (const (undefined, undefined)) input + let intu = Unfold.carryInput $ Unfold.lmap (const (undefined, undefined)) input in result $ Stream.mapM checkPair $ Stream.fairUnfoldEach intu ints unfoldSchedEqn :: Monad m => Unfold m ((), ()) Int -> Stream m Int -> m () unfoldSchedEqn input ints = - let intu = Unfold.carry $ Unfold.lmap (const (undefined, undefined)) input + let intu = Unfold.carryInput $ Unfold.lmap (const (undefined, undefined)) input in result $ Stream.mapM checkPair $ Stream.unfoldSched intu ints fairUnfoldSchedEqn :: Monad m => Unfold m ((), ()) Int -> Stream m Int -> m () fairUnfoldSchedEqn input ints = - let intu = Unfold.carry $ Unfold.lmap (const (undefined, undefined)) input + let intu = Unfold.carryInput $ Unfold.lmap (const (undefined, undefined)) input in result $ Stream.mapM checkPair $ Stream.fairUnfoldSched intu ints diff --git a/benchmark/Streamly/Benchmark/Data/Unfold.hs b/benchmark/Streamly/Benchmark/Data/Unfold.hs index d31dd9ac02..dd2be32984 100644 --- a/benchmark/Streamly/Benchmark/Data/Unfold.hs +++ b/benchmark/Streamly/Benchmark/Data/Unfold.hs @@ -8,6 +8,11 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE ScopedTypeVariables #-} +#undef FUSION_CHECK +#ifdef FUSION_CHECK +{-# OPTIONS_GHC -ddump-simpl -ddump-to-file -dsuppress-all #-} +#endif + #ifdef __HADDOCK_VERSION__ #undef INSPECTION #endif @@ -22,6 +27,7 @@ module Main (main) where import Control.DeepSeq (NFData(..)) import Control.Exception (SomeException, ErrorCall, try) import Data.Char (ord) +import qualified Data.Tuple as Tuple import Data.Word (Word8) import Streamly.Internal.Data.Unfold (Unfold) import System.IO (Handle, hClose) @@ -30,6 +36,7 @@ import System.Random (randomRIO) import qualified Prelude import qualified Streamly.FileSystem.Handle as FH import qualified Streamly.Internal.Data.Fold as FL +import qualified Streamly.Internal.Data.Scanl as Scanl import qualified Streamly.Internal.Data.Unfold as UF import qualified Streamly.Internal.Data.Stream as S import qualified Streamly.Internal.Data.StreamK as K @@ -55,7 +62,7 @@ benchIO name f = bench name $ nfIO $ randomRIO (1,1) >>= f -- generate numbers up to the argument value {-# INLINE source #-} source :: Monad m => Int -> Unfold m Int Int -source n = UF.second n UF.enumerateFromToIntegral +source n = UF.supplySecond n UF.enumerateFromToIntegral ------------------------------------------------------------------------------- -- Benchmark helpers @@ -74,7 +81,7 @@ drainTransformation unf f seed = drainGeneration (f unf) seed drainTransformationDefault :: Monad m => Int -> (Unfold m Int Int -> Unfold m c d) -> c -> m () drainTransformationDefault to = - drainTransformation (UF.second to UF.enumerateFromToIntegral) + drainTransformation (UF.supplySecond to UF.enumerateFromToIntegral) {-# INLINE drainProduct #-} drainProduct :: @@ -97,7 +104,7 @@ drainProductDefault to = drainProduct src src where - src = UF.second to UF.enumerateFromToIntegral + src = UF.supplySecond to UF.enumerateFromToIntegral ------------------------------------------------------------------------------- -- Operations on input @@ -124,7 +131,7 @@ first :: Monad m => Int -> Int -> m () first size start = drainTransformation (UF.take size UF.enumerateFromThenIntegral) - (UF.first start) + (UF.supplyFirst start) 1 {-# INLINE second #-} @@ -132,7 +139,7 @@ second :: Monad m => Int -> Int -> m () second size start = drainTransformation (UF.take size UF.enumerateFromThenIntegral) - (UF.second 1) + (UF.supplySecond 1) start {-# INLINE discardFirst #-} @@ -150,7 +157,7 @@ swap :: Monad m => Int -> Int -> m () swap size start = drainTransformation (UF.take size UF.enumerateFromThenIntegral) - UF.swap + (UF.lmap Tuple.swap) (1, start) ------------------------------------------------------------------------------- @@ -259,7 +266,7 @@ enumerateFromThenIntegral size start = enumerateFromToIntegral :: Monad m => Int -> Int -> m () enumerateFromToIntegral size start = drainGeneration - ( UF.second + ( UF.supplySecond (size + start) UF.enumerateFromToIntegral ) start @@ -283,7 +290,7 @@ enumerateFromToFractional :: Monad m => Int -> Int -> m () enumerateFromToFractional size start = let intToDouble x = (fromInteger (fromIntegral x)) :: Double in drainGeneration - ( UF.second + ( UF.supplySecond (intToDouble $ start + size) UF.enumerateFromToFractional ) @@ -296,7 +303,7 @@ enumerateFromToFractional size start = {-# INLINE postscan #-} postscan :: Monad m => Int -> Int -> m () postscan size start = - drainTransformationDefault (size + start) (UF.postscan FL.sum) start + drainTransformationDefault (size + start) (UF.postscanl Scanl.sum) start {-# INLINE map #-} map :: Monad m => Int -> Int -> m () @@ -312,7 +319,7 @@ mapM2 :: Monad m => Int -> Int -> m () mapM2 size start = drainTransformationDefault size - (UF.mapM (\(a, b) -> return $ a + b) . UF.carry) + (UF.mapM (\(a, b) -> return $ a + b) . UF.carryInput) start ------------------------------------------------------------------------------- @@ -452,8 +459,8 @@ concatMapM inner outer start = where - unfoldInGen i = return (UF.second (i + inner) UF.enumerateFromToIntegral) - unfoldOut = UF.second (start + outer) UF.enumerateFromToIntegral + unfoldInGen i = return (UF.supplySecond (i + inner) UF.enumerateFromToIntegral) + unfoldOut = UF.supplySecond (start + outer) UF.enumerateFromToIntegral {-# INLINE toNull #-} toNull :: Monad m => Int -> Int -> m () @@ -828,6 +835,7 @@ o_1_space_copy_read_exceptions env = main :: IO () main = do +#ifndef FUSION_CHECK env <- mkHandleBenchEnv runWithCLIOpts defaultStreamSize (allBenchmarks env) @@ -847,3 +855,11 @@ main = do , bgroup (o_n_space_prefix moduleName) $ Prelude.concat [o_n_space_nested size] ] +#else + -- Enable FUSION_CHECK macro at the beginning of the file + -- Enable one benchmark below, and run the benchmark + -- Check the .dump-simpl output + let value = 100000 + lmapM value 0 + return () +#endif diff --git a/benchmark/bench-runner/flake.lock b/benchmark/bench-runner/flake.lock index e07465c269..114d59a6ed 100644 --- a/benchmark/bench-runner/flake.lock +++ b/benchmark/bench-runner/flake.lock @@ -7,65 +7,65 @@ "nixpkgs-darwin": "nixpkgs-darwin" }, "locked": { - "lastModified": 1764227617, - "narHash": "sha256-6ufcKQRBK41hzBQPQKHTUqdB5TXYyx4QD3TwaXymHwg=", + "lastModified": 1776414440, + "narHash": "sha256-Be67u+Qea2sEuI+3BVjkc+o4fYgRT/fOANGNAp2OuFk=", "ref": "refs/heads/master", - "rev": "5c3c31fa35f9f75a52e2fd68f7d1d47f7622ce33", - "revCount": 108, + "rev": "69728978adc44f53b3dd907acb2eb5bd2415fd60", + "revCount": 125, "type": "git", "url": "ssh://git@github.com/composewell/streamly-packages" }, "original": { - "rev": "5c3c31fa35f9f75a52e2fd68f7d1d47f7622ce33", + "rev": "69728978adc44f53b3dd907acb2eb5bd2415fd60", "type": "git", "url": "ssh://git@github.com/composewell/streamly-packages" } }, "basepkgs_2": { "locked": { - "lastModified": 1764227406, - "narHash": "sha256-aLI1AFkYWoJAWftnnQwLRiUaZnVIzNY3kkjW5ITigew=", + "lastModified": 1776376172, + "narHash": "sha256-tVn1PuKG+kJGH2PUnV3weRHDnbtgUDlwwSC0K3A45aM=", "owner": "composewell", "repo": "nixpack", - "rev": "b00feebadac4b09a4670c7d68a567dc957f6cb82", + "rev": "f50a0b2aaaab434f46847bc171240957b508b901", "type": "github" }, "original": { "owner": "composewell", "repo": "nixpack", - "rev": "b00feebadac4b09a4670c7d68a567dc957f6cb82", + "rev": "f50a0b2aaaab434f46847bc171240957b508b901", "type": "github" } }, "nixpkgs": { "locked": { - "lastModified": 1761440988, - "narHash": "sha256-2qsow3cQIgZB2g8Cy8cW+L9eXDHP6a1PsvOschk5y+E=", + "lastModified": 1774106199, + "narHash": "sha256-US5Tda2sKmjrg2lNHQL3jRQ6p96cgfWh3J1QBliQ8Ws=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "de69d2ba6c70e747320df9c096523b623d3a4c35", + "rev": "6c9a78c09ff4d6c21d0319114873508a6ec01655", "type": "github" }, "original": { "owner": "NixOS", "repo": "nixpkgs", - "rev": "de69d2ba6c70e747320df9c096523b623d3a4c35", + "rev": "6c9a78c09ff4d6c21d0319114873508a6ec01655", "type": "github" } }, "nixpkgs-darwin": { "locked": { - "lastModified": 1761430225, - "narHash": "sha256-rwI/YwAAByROAXkGbQNsxgUl/UM5eG5N6XIUzBKOIOw=", + "lastModified": 1774106199, + "narHash": "sha256-US5Tda2sKmjrg2lNHQL3jRQ6p96cgfWh3J1QBliQ8Ws=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "08478b816182dc3cc208210b996294411690111d", + "rev": "6c9a78c09ff4d6c21d0319114873508a6ec01655", "type": "github" }, "original": { "owner": "NixOS", "repo": "nixpkgs", - "rev": "08478b816182dc3cc208210b996294411690111d", + "rev": "6c9a78c09ff4d6c21d0319114873508a6ec01655", "type": "github" } }, diff --git a/benchmark/bench-runner/flake.nix b/benchmark/bench-runner/flake.nix index 23798e2772..7d0d078e95 100644 --- a/benchmark/bench-runner/flake.nix +++ b/benchmark/bench-runner/flake.nix @@ -2,7 +2,7 @@ description = "bench-runner"; inputs = { - basepkgs.url = "git+ssh://git@github.com/composewell/streamly-packages?rev=5c3c31fa35f9f75a52e2fd68f7d1d47f7622ce33"; + basepkgs.url = "git+ssh://git@github.com/composewell/streamly-packages?rev=69728978adc44f53b3dd907acb2eb5bd2415fd60"; nixpkgs.follows = "basepkgs/nixpkgs"; nixpkgs-darwin.follows = "basepkgs/nixpkgs-darwin"; }; diff --git a/benchmark/streamly-benchmarks.cabal b/benchmark/streamly-benchmarks.cabal index f096085952..04bfb191b3 100644 --- a/benchmark/streamly-benchmarks.cabal +++ b/benchmark/streamly-benchmarks.cabal @@ -260,8 +260,8 @@ benchmark Data.Array.Generic buildable: False else buildable: True - if flag(limit-build-mem) && !flag(fusion-plugin) - ghc-options: +RTS -M500M -RTS + if flag(limit-build-mem) + ghc-options: +RTS -M600M -RTS benchmark Data.Array.Stream import: bench-options diff --git a/core/src/Streamly/Data/Unfold.hs b/core/src/Streamly/Data/Unfold.hs index 6d0c0aa974..6b417183bc 100644 --- a/core/src/Streamly/Data/Unfold.hs +++ b/core/src/Streamly/Data/Unfold.hs @@ -65,9 +65,9 @@ module Streamly.Data.Unfold -- ** Mapping on Input , lmap , lmapM - , first - , second - , carry + , supplyFirst + , supplySecond + , carryInput -- ** Mapping on Output , mapM @@ -93,6 +93,9 @@ module Streamly.Data.Unfold -- * Deprecated , many + , first + , second + , carry ) where diff --git a/core/src/Streamly/Internal/Data/MutArray.hs b/core/src/Streamly/Internal/Data/MutArray.hs index 95961ec0dd..110286bb15 100644 --- a/core/src/Streamly/Internal/Data/MutArray.hs +++ b/core/src/Streamly/Internal/Data/MutArray.hs @@ -97,7 +97,7 @@ indexerFromLen from len = let fromThenTo n = (from, from + len, n - 1) mkSlice n i = return (i, min len (n - i)) in Unfold.lmap length - $ Unfold.mapM (uncurry mkSlice) . Unfold.carry + $ Unfold.mapM (uncurry mkSlice) . Unfold.carryInput $ Unfold.lmap fromThenTo Unfold.enumerateFromThenTo RENAME(sliceIndexerFromLen,indexerFromLen) @@ -121,7 +121,7 @@ splitterFromLen, slicerFromLen :: forall m a. (Monad m, Unbox a) splitterFromLen from len = let mkSlice arr (i, n) = return $ unsafeSliceOffLen i n arr in Unfold.mapM (uncurry mkSlice) - $ Unfold.carry (indexerFromLen from len) + $ Unfold.carryInput (indexerFromLen from len) RENAME(slicerFromLen,splitterFromLen) {-# DEPRECATED getSlicesFromLen "Please use splitterFromLen instead." #-} diff --git a/core/src/Streamly/Internal/Data/Stream/Nesting.hs b/core/src/Streamly/Internal/Data/Stream/Nesting.hs index d7d70156e8..112da4e06e 100644 --- a/core/src/Streamly/Internal/Data/Stream/Nesting.hs +++ b/core/src/Streamly/Internal/Data/Stream/Nesting.hs @@ -1344,7 +1344,7 @@ schedFor = flip schedMap -- -- >>> :{ -- outerLoop = Stream.fromList [1,2,3] --- innerLoop = Unfold.carry $ Unfold.lmap (const [4,5,6]) Unfold.fromList +-- innerLoop = Unfold.carryInput $ Unfold.lmap (const [4,5,6]) Unfold.fromList -- :} -- -- >>> Stream.toList $ Stream.fairUnfoldSched innerLoop outerLoop @@ -1398,7 +1398,7 @@ fairUnfoldSched (Unfold istep inject) (Stream ostep ost) = -- -- >>> :{ -- outerLoop = Stream.fromList [1,2,3] --- innerLoop = Unfold.carry $ Unfold.lmap (const [4,5,6]) Unfold.fromList +-- innerLoop = Unfold.carryInput $ Unfold.lmap (const [4,5,6]) Unfold.fromList -- :} -- -- >>> Stream.toList $ Stream.fairUnfoldEach innerLoop outerLoop diff --git a/core/src/Streamly/Internal/Data/Stream/Type.hs b/core/src/Streamly/Internal/Data/Stream/Type.hs index a43b33ca47..ee2f054baa 100644 --- a/core/src/Streamly/Internal/Data/Stream/Type.hs +++ b/core/src/Streamly/Internal/Data/Stream/Type.hs @@ -1534,7 +1534,7 @@ loop = crossWith (\b a -> (a,b)) loopBy :: Monad m => Unfold m x b -> x -> Stream m a -> Stream m (a, b) loopBy u x s = let u1 = Unfold.lmap snd u - u2 = Unfold.map (first fst) (Unfold.carry u1) + u2 = Unfold.map (first fst) (Unfold.carryInput u1) in unfoldEach u2 $ fmap (, x) s ------------------------------------------------------------------------------ @@ -1573,7 +1573,7 @@ data UnfoldEachState o i = -- flip Stream.mapM (Stream.fromList [1,2,3]) $ \x -> do -- liftIO $ putStrLn (show x) -- return x --- innerUnfold = Unfold.carry $ Unfold.lmap (const [4,5,6]) Unfold.fromList +-- innerUnfold = Unfold.carryInput $ Unfold.lmap (const [4,5,6]) Unfold.fromList -- innerLoop = -- flip Unfold.mapM innerUnfold $ \(x, y) -> do -- when (x == 1) $ liftIO $ putStrLn (show y) diff --git a/core/src/Streamly/Internal/Data/Unfold.hs b/core/src/Streamly/Internal/Data/Unfold.hs index 2feccc9e56..20e066ce92 100644 --- a/core/src/Streamly/Internal/Data/Unfold.hs +++ b/core/src/Streamly/Internal/Data/Unfold.hs @@ -50,9 +50,12 @@ module Streamly.Internal.Data.Unfold -- * Combinators -- ** Mapping on Input - , discardFirst - , discardSecond - , swap + + -- A named lmap specialization earns its name only if it's more + -- forward-thinkable than lmap f itself. + + , discardFirst -- asSecond + , discardSecond -- asFirst -- coapply -- comonad @@ -60,8 +63,7 @@ module Streamly.Internal.Data.Unfold , fold -- ** Mapping on Output - , postscanlM' - , postscan + , postscanl , scanl , scanlMany , foldMany @@ -77,6 +79,9 @@ module Streamly.Internal.Data.Unfold , drop , dropWhile , dropWhileM + , mapMaybe + , mapMaybeM + , catMaybes -- ** Cross product , innerJoin @@ -109,8 +114,11 @@ module Streamly.Internal.Data.Unfold , handle -- ** Deprecated + , postscan + , postscanlM' , scan , scanMany + , swap ) where @@ -131,6 +139,7 @@ import Streamly.Internal.Data.SVar.Type (defState) import qualified Control.Monad.Catch as MC import qualified Data.Tuple as Tuple import qualified Streamly.Internal.Data.Fold.Type as FL +import qualified Streamly.Internal.Data.Scanl.Type as Scanl import qualified Streamly.Internal.Data.Stream.Type as D import qualified Streamly.Internal.Data.StreamK.Type as K import qualified Prelude @@ -187,6 +196,7 @@ discardSecond = lmap fst -- -- /Pre-release/ -- +{-# DEPRECATED swap "Please use \"lmap Tuple.swap\" instead" #-} {-# INLINE_NORMAL swap #-} swap :: Unfold m (a, c) b -> Unfold m (c, a) b swap = lmap Tuple.swap @@ -317,13 +327,14 @@ either (Unfold stepL injectL) (Unfold stepR injectR) = Unfold step inject -- postscan2 :: Monad m => Refold m a b c -> Unfold m a b -> Unfold m a c --- | Scan the output of an 'Unfold' to change it in a stateful manner. +-- | Scan the output of an 'Unfold' to change it in a stateful manner, using a +-- 'Scanl'. The initial value of the scan is not emitted in the output. -- -- /Pre-release/ -{-# INLINE_NORMAL postscan #-} -postscan :: Monad m => Fold m b c -> Unfold m a b -> Unfold m a c -postscan (Fold stepF initial extract final) (Unfold stepU injectU) = - Unfold step inject +{-# INLINE_NORMAL postscanl #-} +postscanl :: Monad m => Scanl m b c -> Unfold m a b -> Unfold m a c +postscanl (Scanl stepF initial extract final) (Unfold stepU injectU) = + mkUnfoldM step inject where @@ -349,6 +360,12 @@ postscan (Fold stepF initial extract final) (Unfold stepU injectU) = step Nothing = return Stop +-- When we remove extract from Fold this function should be removed. +{-# DEPRECATED postscan "Please use postscanl instead" #-} +{-# INLINE_NORMAL postscan #-} +postscan :: Monad m => Fold m b c -> Unfold m a b -> Unfold m a c +postscan (Fold s i e f) = postscanl (Scanl s i e f) + data ScanState s f = ScanInit s | ScanDo s !f | ScanDone {-# INLINE_NORMAL scanWith #-} @@ -419,12 +436,10 @@ scanl = scanWith False scan :: Monad m => Fold m b c -> Unfold m a b -> Unfold m a c scan (Fold s i e f) = scanWith False (Scanl s i e f) --- | Scan the output of an 'Unfold' to change it in a stateful manner. --- --- /Pre-release/ +{-# DEPRECATED postscanlM' "Please use \"postscanl (Scanl.scanlM' f z)\" instead" #-} {-# INLINE_NORMAL postscanlM' #-} postscanlM' :: Monad m => (b -> a -> m b) -> m b -> Unfold m c a -> Unfold m c b -postscanlM' f z = postscan (FL.foldlM' f z) +postscanlM' f z = postscanl (Scanl.mkScanlM f z) ------------------------------------------------------------------------------- -- Convert streams into unfolds @@ -562,7 +577,7 @@ repeat = lmap pure repeatM -- | Takes a tuple whose first element is repeated and the second element is -- passed through the supplied unfold. -- --- >>> zipRepeat = fmap (\(x,y) -> (fst x, y)) . Unfold.carry . Unfold.lmap snd +-- >>> zipRepeat = fmap (\(x,y) -> (fst x, y)) . Unfold.carryInput . Unfold.lmap snd -- >>> zipRepeat = Unfold.zipArrowWith (,) Unfold.repeat -- {-# INLINE_NORMAL zipRepeat #-} @@ -640,6 +655,7 @@ take n (Unfold step1 inject1) = Unfold step inject -- {-# INLINE_NORMAL filterM #-} filterM :: Monad m => (b -> m Bool) -> Unfold m a b -> Unfold m a b +-- filterM p = mapMaybeM (\x -> fmap (\b -> if b then Just x else Nothing) (p x)) filterM f (Unfold step1 inject1) = Unfold step inject1 where {-# INLINE_LATE step #-} @@ -720,6 +736,58 @@ dropWhileM f (Unfold step inject) = Unfold step' inject' dropWhile :: Monad m => (b -> Bool) -> Unfold m a b -> Unfold m a b dropWhile f = dropWhileM (return . f) +------------------------------------------------------------------------------ +-- Maybe Unfolds +------------------------------------------------------------------------------ + +-- Note: do not define in terms of "filter", avoid partial fromJust. +-- instead define filter in terms of mapMaybe. + +-- | Like 'mapMaybe' but maps a monadic function. +-- +-- Definition: +-- +-- >>> mapMaybeM f = Unfold.catMaybes . Unfold.mapM f +-- +{-# INLINE_NORMAL mapMaybeM #-} +mapMaybeM :: Monad m => (b -> m (Maybe c)) -> Unfold m a b -> Unfold m a c +mapMaybeM f (Unfold step1 inject1) = Unfold step inject1 + where + {-# INLINE_LATE step #-} + step st = do + r <- step1 st + case r of + Yield x s -> do + b <- f x + return $ case b of + Just c -> Yield c s + Nothing -> Skip s + Skip s -> return $ Skip s + Stop -> return Stop + +-- | Map a 'Maybe' returning function on the output of the unfold, filter out +-- the 'Nothing' elements, and return an unfold yielding the values extracted +-- from 'Just'. +-- +-- Definition: +-- +-- >>> mapMaybe f = Unfold.catMaybes . fmap f +-- +{-# INLINE mapMaybe #-} +mapMaybe :: Monad m => (b -> Maybe c) -> Unfold m a b -> Unfold m a c +mapMaybe f = mapMaybeM (return . f) + +-- | In an unfold whose output is a 'Maybe', discard 'Nothing's and unwrap +-- 'Just's. +-- +-- Definition: +-- +-- >>> catMaybes = Unfold.mapMaybe id +-- +{-# INLINE catMaybes #-} +catMaybes :: Monad m => Unfold m a (Maybe b) -> Unfold m a b +catMaybes = mapMaybe id + -- | Cross intersection of two unfolds. See -- 'Streamly.Internal.Data.Stream.innerJoin' for more details. {-# INLINE_NORMAL innerJoin #-} diff --git a/core/src/Streamly/Internal/Data/Unfold/Enumeration.hs b/core/src/Streamly/Internal/Data/Unfold/Enumeration.hs index ce75c44b62..8e0e9f9ceb 100644 --- a/core/src/Streamly/Internal/Data/Unfold/Enumeration.hs +++ b/core/src/Streamly/Internal/Data/Unfold/Enumeration.hs @@ -65,7 +65,7 @@ import Data.Ratio import Data.Word import Numeric.Natural import Data.Functor.Identity (Identity(..)) -import Streamly.Internal.Data.Unfold.Type +import Streamly.Internal.Data.Unfold.Type hiding (takeWhileMWithInput) import Prelude hiding (map, mapM, takeWhile, take, filter, const, zipWith , drop, dropWhile) @@ -176,6 +176,11 @@ enumerateFromNum = lmap (\from -> (from, 1)) enumerateFromStepNum -- Enumeration of Integrals ------------------------------------------------------------------------------ +{-# INLINE takeWhileMWithInput #-} +takeWhileMWithInput :: Monad m => + (a -> b -> m Bool) -> Unfold m a b -> Unfold m a b +takeWhileMWithInput f = map snd . takeWhileM (uncurry f) . carryInput + -- | Can be used to enumerate unbounded integrals. This does not check for -- overflow or underflow for bounded integrals. -- @@ -226,7 +231,7 @@ enumerateFromThenToIntegral = {-# INLINE enumerateFromIntegralBounded #-} enumerateFromIntegralBounded :: (Monad m, Integral a, Bounded a) => Unfold m a a -enumerateFromIntegralBounded = second maxBound enumerateFromToIntegral +enumerateFromIntegralBounded = supplySecond maxBound enumerateFromToIntegral {-# INLINE enumerateFromThenIntegralBounded #-} enumerateFromThenIntegralBounded :: (Monad m, Integral a, Bounded a ) => @@ -351,7 +356,7 @@ enumerateFromThenToSmall = -- {-# INLINE enumerateFromSmallBounded #-} enumerateFromSmallBounded :: (Monad m, Enum a, Bounded a) => Unfold m a a -enumerateFromSmallBounded = second maxBound enumerateFromToSmall +enumerateFromSmallBounded = supplySecond maxBound enumerateFromToSmall -- | Enumerate from given starting Enum value 'from' and next Enum value 'next' -- with stride of (fromEnum next - fromEnum from) till maxBound. diff --git a/core/src/Streamly/Internal/Data/Unfold/Type.hs b/core/src/Streamly/Internal/Data/Unfold/Type.hs index d94822a04d..d1d16a0aca 100644 --- a/core/src/Streamly/Internal/Data/Unfold/Type.hs +++ b/core/src/Streamly/Internal/Data/Unfold/Type.hs @@ -47,14 +47,19 @@ module Streamly.Internal.Data.Unfold.Type Step(..) , Unfold (..) + -- Constructor Naming: + -- - "mk" prefix marks the primitive constructors. Use mkUnfoldM vs unfold + -- because it would collide with 'Data.Stream.unfold'. + -- - Bare names follow Data.List APIs. + -- - Suffixes track the variants + -- * Basic Constructors , mkUnfoldM - , mkUnfoldrM , unfoldrM , unfoldr , functionM , function - , functionMaybeM + , functionMaybeM -- XXX remove in favor of catMaybes functionM? , identity -- * From Values @@ -66,14 +71,14 @@ module Streamly.Internal.Data.Unfold.Type , fromTuple -- * Transformations - , lmap - , lmapM + , lmap -- XXX plug + , lmapM -- XXX plugM , map , mapM - , supply -- input or useInput - , first -- asFirst - , second --asSecond - , carry -- XXX carryInput? + , supply + , supplyFirst + , supplySecond + , carryInput , consInput , consInputWith @@ -109,6 +114,7 @@ module Streamly.Internal.Data.Unfold.Type , zipWith -- * Deprecated + , mkUnfoldrM , many , many2 , manyInterleave @@ -116,20 +122,23 @@ module Streamly.Internal.Data.Unfold.Type , mapM2 , takeWhileMWithInput , both + , first + , second + , carry ) where #include "deprecation.h" #include "inline.hs" --- import Control.Arrow (Arrow(..)) --- import Control.Category (Category(..)) +-- import Control.Arrow (Arrow(arr, (***))) +import Control.Category (Category(id, (.))) import Control.Monad ((>=>)) import Data.Void (Void) import Fusion.Plugin.Types (Fuse(..)) import Streamly.Internal.Data.Stream.Step (Step(..)) -import Prelude hiding (map, mapM, concatMap, zipWith, takeWhile) +import Prelude hiding (id, (.), map, mapM, concatMap, zipWith, takeWhile) #include "DocTestDataUnfold.hs" @@ -245,7 +254,7 @@ mkUnfoldM = Unfold -- -- See also: 'unfoldrM' -- --- /Pre-release/ +{-# DEPRECATED mkUnfoldrM "Use mkUnfoldM with pure as the inject function instead." #-} {-# INLINE mkUnfoldrM #-} mkUnfoldrM :: Applicative m => (a -> m (Step a b)) -> Unfold m a b mkUnfoldrM step = Unfold step pure @@ -298,7 +307,7 @@ unfoldr step = unfoldrM (pure . step) -- {-# INLINE_NORMAL lmap #-} lmap :: (a -> c) -> Unfold m c b -> Unfold m a b -lmap f (Unfold ustep uinject) = Unfold ustep (uinject Prelude.. f) +lmap f (Unfold ustep uinject) = Unfold ustep (uinject . f) -- | Map an action on the input argument of the 'Unfold'. -- @@ -330,39 +339,44 @@ both a = lmap (Prelude.const a) -- as a seed. -- -- @ --- first a = Unfold.lmap (a, ) +-- supplyFirst a = Unfold.lmap (a, ) -- @ -- -- /Pre-release/ -- -{-# INLINE_NORMAL first #-} -first :: a -> Unfold m (a, b) c -> Unfold m b c -first a = lmap (a, ) +{-# INLINE_NORMAL supplyFirst #-} +supplyFirst, first :: a -> Unfold m (a, b) c -> Unfold m b c +supplyFirst a = lmap (a, ) + +RENAME(first,supplyFirst) -- | Supply the second component of the tuple to an unfold that accepts a tuple -- as a seed resulting in a fold that accepts the first component of the tuple -- as a seed. -- -- @ --- second b = Unfold.lmap (, b) +-- supplySecond b = Unfold.lmap (, b) -- @ -- -- /Pre-release/ -- -{-# INLINE_NORMAL second #-} -second :: b -> Unfold m (a, b) c -> Unfold m a c -second b = lmap (, b) +{-# INLINE_NORMAL supplySecond #-} +supplySecond, second :: b -> Unfold m (a, b) c -> Unfold m a c +supplySecond b = lmap (, b) + +RENAME(second,supplySecond) ------------------------------------------------------------------------------ -- Filter input ------------------------------------------------------------------------------ -- | --- >>> takeWhileMWithInput f u = Unfold.map snd $ Unfold.takeWhileM (\(a,b) -> f a b) (Unfold.carry u) +-- >>> takeWhileMWithInput f u = Unfold.map snd $ Unfold.takeWhileM (\(a,b) -> f a b) (Unfold.carryInput u) +{-# DEPRECATED takeWhileMWithInput "Use \"map snd . takeWhileM (uncurry f) . carryInput\" instead." #-} {-# INLINE_NORMAL takeWhileMWithInput #-} takeWhileMWithInput :: Monad m => (a -> b -> m Bool) -> Unfold m a b -> Unfold m a b -takeWhileMWithInput f u = map snd $ takeWhileM (\(a,b) -> f a b) (carry u) +takeWhileMWithInput f u = map snd $ takeWhileM (\(a,b) -> f a b) (carryInput u) {- takeWhileMWithInput f (Unfold step1 inject1) = Unfold step inject @@ -414,10 +428,10 @@ takeWhile f = takeWhileM (return . f) -- Functor ------------------------------------------------------------------------------ -{-# DEPRECATED mapM2 "Use carry with mapM instead." #-} +{-# DEPRECATED mapM2 "Use carryInput with mapM instead." #-} {-# INLINE_NORMAL mapM2 #-} mapM2 :: Monad m => (a -> b -> m c) -> Unfold m a b -> Unfold m a c -mapM2 f = mapM (uncurry f) . carry +mapM2 f = mapM (uncurry f) . carryInput {- mapM2 f (Unfold ustep uinject) = Unfold step inject where @@ -453,15 +467,15 @@ mapM f (Unfold ustep uinject) = Unfold step uinject -- | Carry the input along with the output as the first element of the output -- tuple. -- --- carry = Unfold.lmap (\x -> (x,x)) . Unfold.zipRepeat +-- carryInput = Unfold.lmap (\x -> (x,x)) . Unfold.zipRepeat -- -- Note that the input seed may mutate (e.g. if the seed is a Handle or IORef) -- as stream is generated from it, so we need to be careful when reusing the -- seed while the stream is being generated from it. -- -{-# INLINE_NORMAL carry #-} -carry :: Functor m => Unfold m a b -> Unfold m a (a,b) -carry (Unfold ustep uinject) = Unfold step (\a -> (a,) <$> uinject a) +{-# INLINE_NORMAL carryInput #-} +carryInput, carry :: Functor m => Unfold m a b -> Unfold m a (a,b) +carryInput (Unfold ustep uinject) = Unfold step (\a -> (a,) <$> uinject a) where @@ -474,6 +488,8 @@ carry (Unfold ustep uinject) = Unfold step (\a -> (a,) <$> uinject a) {-# INLINE_LATE step #-} step (a, st) = fmap (func a) (ustep st) +RENAME(carry,carryInput) + {-# ANN type ConsInputState Fuse #-} data ConsInputState a s = ConsInputFirst a s | ConsInputRest s @@ -508,10 +524,10 @@ consInputWith f (Unfold ustep uinject) = Unfold step inject consInput :: Applicative m => Unfold m a a -> Unfold m a a consInput = consInputWith id -{-# DEPRECATED map2 "Use carry with map instead." #-} +{-# DEPRECATED map2 "Use carryInput with map instead." #-} {-# INLINE_NORMAL map2 #-} map2 :: Functor m => (a -> b -> c) -> Unfold m a b -> Unfold m a c -map2 f = map (uncurry f) . carry +map2 f = map (uncurry f) . carryInput -- | Map a function on the output of the unfold (the type @b@). -- @@ -562,7 +578,7 @@ fromEffect m = Unfold step inject -- /Pre-release/ {-# INLINE fromPure #-} fromPure :: Applicative m => b -> Unfold m a b -fromPure = fromEffect Prelude.. pure +fromPure = fromEffect . pure data TupleState a = TupleBoth a a | TupleOne a | TupleNone @@ -617,11 +633,11 @@ crossApplyFst (Unfold _step1 _inject1) (Unfold _step2 _inject2) = undefined data Many2State x s1 s2 = Many2Outer x s1 | Many2Inner x s1 s2 -} -{-# DEPRECATED many2 "Use carry with unfoldEach instead." #-} +{-# DEPRECATED many2 "Use carryInput with unfoldEach instead." #-} {-# INLINE_NORMAL many2 #-} many2 :: Monad m => Unfold m (a, b) c -> Unfold m a b -> Unfold m a c -many2 u1 u2 = unfoldEach u1 (carry u2) +many2 u1 u2 = unfoldEach u1 (carryInput u2) {- unfoldEach2 (Unfold step2 inject2) (Unfold step1 inject1) = Unfold step inject @@ -651,7 +667,7 @@ unfoldEach2 (Unfold step2 inject2) (Unfold step1 inject1) = Unfold step inject data Cross a s1 b s2 = CrossOuter a s1 | CrossInner a s1 b s2 --- >> f1 f u = Unfold.mapM (\((_, c), b) -> f b c) Unfold.carry (Unfold.lmap fst u)) +-- >> f1 f u = Unfold.mapM (\((_, c), b) -> f b c) Unfold.carryInput (Unfold.lmap fst u)) -- >> crossWithM f u = Unfold.unfoldEach2 (f1 f u) -- | Create a cross product (vector product or cartesian product) of the @@ -857,7 +873,7 @@ concatMapM f (Unfold step1 inject1) = Unfold step inject {-# INLINE concatMap #-} concatMap :: Monad m => (b -> Unfold m a c) -> Unfold m a b -> Unfold m a c -concatMap f = concatMapM (return Prelude.. f) +concatMap f = concatMapM (return . f) infixl 1 `bind` @@ -921,11 +937,13 @@ functionM f = Unfold step inject -- {-# INLINE function #-} function :: Applicative m => (a -> b) -> Unfold m a b -function f = functionM $ pure Prelude.. f +function f = functionM $ pure . f -- | Lift a monadic Maybe returning function into an unfold. The unfold -- generates a singleton stream. -- +-- >>> functionMaybeM = Unfold.catMaybes . Unfold.functionM +-- {-# INLINE functionMaybeM #-} functionMaybeM :: Monad m => (a -> m (Maybe b)) -> Unfold m a b functionMaybeM f = Unfold step inject @@ -935,23 +953,18 @@ functionMaybeM f = Unfold step inject inject a = return (Just a) {-# INLINE_LATE step #-} - step (Just a) = do - result <- f a - case result of - Just b -> pure $ Yield b Nothing - Nothing -> pure Stop - + step (Just a) = maybe Stop (`Yield` Nothing) <$> f a step Nothing = pure Stop -- | Identity unfold. The unfold generates a singleton stream having the input -- as the only element. -- --- > identity = function Prelude.id +-- > identity = function id -- -- /Pre-release/ {-# INLINE identity #-} identity :: Applicative m => Unfold m a a -identity = function Prelude.id +identity = function id {-# ANN type ConcatState Fuse #-} data ConcatState s1 s2 = ConcatOuter s1 | ConcatInner s1 s2 @@ -990,8 +1003,8 @@ unfoldEach (Unfold step2 inject2) (Unfold step1 inject1) = Unfold step inject RENAME(many,unfoldEach) {- --- XXX There are multiple possible ways to combine the unfolds, "many" appends --- them, we could also have other variants of "many" e.g. manyInterleave. +-- XXX There are multiple possible ways to combine the unfolds, "unfoldEach" +-- appends them, we could also have other variants e.g. unfoldEachInterleave. -- Should we even have a category instance or just use these functions -- directly? -- @@ -1000,7 +1013,7 @@ instance Monad m => Category (Unfold m) where id = identity {-# INLINE (.) #-} - (.) = many + (.) = unfoldEach -} ------------------------------------------------------------------------------- @@ -1110,24 +1123,27 @@ zipArrowWith f = zipArrowWithM (\a b -> return (f a b)) -- could zip, merge, append and more. What is the preferred way for Arrow -- instance? Should we even have an arrow instance or just use these functions -- directly? + +-- | '***' splits the input tuple between the two unfolds and zips their +-- outputs (same as @Unfold.zipArrowWith (,)@). The default '&&&' distributes +-- the same input to both unfolds and zips their outputs (same as +-- @Unfold.zipWith (,)@). -- --- | '***' is a zip like operation, in fact it is the same as @Unfold.zipWith --- (,)@, '&&&' is a tee like operation i.e. distributes the input to both the --- unfolds and then zips the output. --- -{-# ANN module "HLint: ignore Use zip" #-} instance Monad m => Arrow (Unfold m) where {-# INLINE arr #-} arr = function {-# INLINE (***) #-} - u1 *** u2 = zipWith (,) (lmap fst u1) (lmap snd u2) + (***) = zipArrowWith (,) -} ------------------------------------------------------------------------------ -- Interleaving ------------------------------------------------------------------------------ +-- XXX If we have interleave, we can have append as well and all binary +-- operations that streams have. + -- We can possibly have an "interleave" operation to interleave the streams -- from two seeds: -- diff --git a/core/src/Streamly/Internal/FileSystem/DirIO.hs b/core/src/Streamly/Internal/FileSystem/DirIO.hs index 02c519e9b1..32959ba648 100644 --- a/core/src/Streamly/Internal/FileSystem/DirIO.hs +++ b/core/src/Streamly/Internal/FileSystem/DirIO.hs @@ -190,7 +190,7 @@ toChunks = toChunksWithBufferOf defaultChunkSize -- @since 0.7.0 {-# INLINE readChunks #-} readChunks :: MonadIO m => Unfold m Handle (Array Word8) -readChunks = UF.first readChunksWithBufferOf defaultChunkSize +readChunks = UF.supplyFirst defaultChunkSize readChunksWithBufferOf ------------------------------------------------------------------------------- -- Read a Directory to Stream @@ -243,7 +243,7 @@ eitherReaderPaths ::(MonadIO m, MonadCatch m) => (ReadOptions -> ReadOptions) -> eitherReaderPaths f = let () = Path.join in fmap (\(dir, x) -> bimap (dir ) (dir ) x) - $ UF.carry (OS.eitherReader f) + $ UF.carryInput (OS.eitherReader f) -- -- | Read files only. diff --git a/core/src/Streamly/Internal/FileSystem/Handle.hs b/core/src/Streamly/Internal/FileSystem/Handle.hs index 9b5d10cc01..d4e4ef9a5d 100644 --- a/core/src/Streamly/Internal/FileSystem/Handle.hs +++ b/core/src/Streamly/Internal/FileSystem/Handle.hs @@ -304,11 +304,11 @@ readChunks = readChunksWith defaultChunkSize -- size of arrays in the resulting stream are therefore less than or equal to -- 'Streamly.Internal.Data.Array.Type.defaultChunkSize'. -- --- >>> chunkReader = Unfold.first IO.defaultChunkSize Handle.chunkReaderWith +-- >>> chunkReader = Unfold.supplyFirst IO.defaultChunkSize Handle.chunkReaderWith -- {-# INLINE chunkReader #-} chunkReader :: MonadIO m => Unfold m Handle (Array Word8) -chunkReader = UF.first defaultChunkSize chunkReaderWith +chunkReader = UF.supplyFirst defaultChunkSize chunkReaderWith ------------------------------------------------------------------------------- -- Read File to Stream diff --git a/hie.yaml b/hie.yaml index dfb0ac6157..8d696fdce3 100644 --- a/hie.yaml +++ b/hie.yaml @@ -24,8 +24,6 @@ cradle: cabal: - path: "./benchmark/lib/" component: "lib:streamly-benchmarks" - - path: "./benchmark/NanoBenchmarks.hs" - component: "exe:nano-bench" - path: "./benchmark/Streamly/Benchmark/Data/Array.hs" component: "bench:Data.Array" - path: "./benchmark/Streamly/Benchmark/Data/Array/Generic.hs" @@ -64,12 +62,18 @@ cradle: component: "bench:Data.Stream" - path: "./benchmark/Streamly/Benchmark/Data/Stream/Prelude/Adaptive.hs" component: "bench:Data.Stream.Adaptive" + - path: "./benchmark/Streamly/Benchmark/Data/Stream/Prelude/Concurrent.hs" + component: "bench:Data.Stream.Concurrent" + - path: "./benchmark/Streamly/Benchmark/Data/Stream/Prelude/ConcurrentEager.hs" + component: "bench:Data.Stream.ConcurrentEager" + - path: "./benchmark/Streamly/Benchmark/Data/Stream/Prelude/ConcurrentInterleaved.hs" + component: "bench:Data.Stream.ConcurrentInterleaved" + - path: "./benchmark/Streamly/Benchmark/Data/Stream/Prelude/ConcurrentOrdered.hs" + component: "bench:Data.Stream.ConcurrentOrdered" - path: "./benchmark/Streamly/Benchmark/Data/Stream/Prelude/ConcurrentThreadHeavy.hs" component: "bench:Data.Stream.ConcurrentThreadHeavy" - path: "./benchmark/Streamly/Benchmark/Data/Stream/Prelude/Exceptions.hs" component: "bench:Data.Stream.Prelude" - - path: "./benchmark/Streamly/Benchmark/Data/Stream/Prelude/Exceptions.hs" - component: "bench:Data.Stream.Prelude.Exceptions" - path: "./benchmark/Streamly/Benchmark/Data/Stream/Prelude/Rate.hs" component: "bench:Data.Stream.Rate" - path: "./benchmark/Streamly/Benchmark/Data/StreamK.hs" @@ -88,6 +92,8 @@ cradle: component: "bench:Data.Unfold.Prelude" - path: "./benchmark/Streamly/Benchmark/FileSystem/DirIO.hs" component: "bench:FileSystem.DirIO" + - path: "./benchmark/Streamly/Benchmark/FileSystem/Handle.hs" + component: "bench:FileSystem.Handle" - path: "./benchmark/Streamly/Benchmark/FileSystem/Handle/Read.hs" component: "bench:FileSystem.Handle" - path: "./benchmark/Streamly/Benchmark/FileSystem/Handle/ReadWrite.hs" diff --git a/src/Streamly/Internal/Network/Inet/TCP.hs b/src/Streamly/Internal/Network/Inet/TCP.hs index e55f014f37..61fd14043c 100644 --- a/src/Streamly/Internal/Network/Inet/TCP.hs +++ b/src/Streamly/Internal/Network/Inet/TCP.hs @@ -182,17 +182,17 @@ acceptorOnAddr = acceptorOnAddrWith [] acceptorWith :: MonadIO m => [(SocketOption, Int)] -> Unfold m PortNumber Socket -acceptorWith opts = UF.first (0,0,0,0) (acceptorOnAddrWith opts) +acceptorWith opts = UF.supplyFirst (0,0,0,0) (acceptorOnAddrWith opts) -- | Like 'acceptorOnAddr' but binds on the IPv4 address @0.0.0.0@ i.e. on all -- IPv4 addresses/interfaces of the machine and listens for TCP connections on -- the specified port. -- --- >>> acceptor = Unfold.first (0,0,0,0) TCP.acceptorOnAddr +-- >>> acceptor = Unfold.supplyFirst (0,0,0,0) TCP.acceptorOnAddr -- {-# INLINE acceptor #-} acceptor :: MonadIO m => Unfold m PortNumber Socket -acceptor = UF.first (0,0,0,0) acceptorOnAddr +acceptor = UF.supplyFirst (0,0,0,0) acceptorOnAddr {-# DEPRECATED acceptorOnPort "Use \"acceptor\" instead." #-} {-# INLINE acceptorOnPort #-} @@ -203,11 +203,11 @@ acceptorOnPort = acceptor -- server can only be accessed from the local host, it cannot be accessed from -- other hosts on the network. -- --- >>> acceptorLocal = Unfold.first (127,0,0,1) TCP.acceptorOnAddr +-- >>> acceptorLocal = Unfold.supplyFirst (127,0,0,1) TCP.acceptorOnAddr -- {-# INLINE acceptorLocal #-} acceptorLocal :: MonadIO m => Unfold m PortNumber Socket -acceptorLocal = UF.first (127,0,0,1) acceptorOnAddr +acceptorLocal = UF.supplyFirst (127,0,0,1) acceptorOnAddr {-# DEPRECATED acceptorOnPortLocal "Use \"acceptorLocal\" instead." #-} {-# INLINE acceptorOnPortLocal #-} diff --git a/src/Streamly/Internal/Network/Socket.hs b/src/Streamly/Internal/Network/Socket.hs index 52880b769e..722ace7269 100644 --- a/src/Streamly/Internal/Network/Socket.hs +++ b/src/Streamly/Internal/Network/Socket.hs @@ -390,7 +390,7 @@ readChunksWithBufferOf = chunkReaderWith -- {-# INLINE chunkReader #-} chunkReader :: MonadIO m => Unfold m Socket (Array Word8) -chunkReader = UF.first defaultChunkSize chunkReaderWith +chunkReader = UF.supplyFirst defaultChunkSize chunkReaderWith ------------------------------------------------------------------------------- -- Read File to Stream @@ -436,7 +436,7 @@ readWithBufferOf = readerWith -- {-# INLINE reader #-} reader :: MonadIO m => Unfold m Socket Word8 -reader = UF.first defaultChunkSize readerWith +reader = UF.supplyFirst defaultChunkSize readerWith ------------------------------------------------------------------------------- -- Writing diff --git a/test/Streamly/Test/Data/Stream/Serial.hs b/test/Streamly/Test/Data/Stream/Serial.hs index 314b808431..73098676c4 100644 --- a/test/Streamly/Test/Data/Stream/Serial.hs +++ b/test/Streamly/Test/Data/Stream/Serial.hs @@ -489,7 +489,7 @@ unfold :: Property unfold = monadicIO $ do a <- pick $ choose (0, max_length `div` 2) b <- pick $ choose (0, max_length) - let unf = UF.second b UF.enumerateFromToIntegral + let unf = UF.supplySecond b UF.enumerateFromToIntegral ls <- toList $ S.unfold unf a return $ ls == [a..b] diff --git a/test/Streamly/Test/Data/Stream/Type.hs b/test/Streamly/Test/Data/Stream/Type.hs index 84ab0f5662..8076a86f9c 100644 --- a/test/Streamly/Test/Data/Stream/Type.hs +++ b/test/Streamly/Test/Data/Stream/Type.hs @@ -29,7 +29,7 @@ unfold :: Property unfold = monadicIO $ do a <- pick $ choose (0, max_length `div` 2) b <- pick $ choose (0, max_length) - let unf = Unfold.second b Unfold.enumerateFromToIntegral + let unf = Unfold.supplySecond b Unfold.enumerateFromToIntegral ls <- toList $ Stream.unfold unf a return $ ls == [a..b] diff --git a/test/Streamly/Test/Data/Unfold.hs b/test/Streamly/Test/Data/Unfold.hs index fd7bdf7ae9..969b7c7020 100644 --- a/test/Streamly/Test/Data/Unfold.hs +++ b/test/Streamly/Test/Data/Unfold.hs @@ -12,8 +12,10 @@ module Main (main) where import Streamly.Internal.Data.Unfold (Unfold) import qualified Data.List as List +import qualified Data.Tuple as Tuple import qualified Prelude import qualified Streamly.Internal.Data.Fold as Fold +import qualified Streamly.Internal.Data.Scanl as Scanl import qualified Streamly.Internal.Data.Unfold as UF import qualified Streamly.Internal.Data.Stream as S import qualified Streamly.Internal.Data.Stream as D @@ -77,12 +79,12 @@ both = first :: Bool first = - let unf = UF.first 1 (UF.function id) + let unf = UF.supplyFirst 1 (UF.function id) in testUnfold unf 2 ([(1, 2)] :: [(Int, Int)]) second :: Bool second = - let unf = UF.second 1 (UF.function id) + let unf = UF.supplySecond 1 (UF.function id) in testUnfold unf 2 ([(2, 1)] :: [(Int, Int)]) discardFirst :: Bool @@ -97,7 +99,7 @@ discardSecond = swap :: Bool swap = - let unf = UF.swap (UF.function id) + let unf = UF.lmap Tuple.swap (UF.function id) in testUnfold unf ((1, 2) :: (Int, Int)) [(2, 1)] consInput :: Bool @@ -459,7 +461,7 @@ postscan :: Property postscan = property $ \(ls :: [Int]) -> - let unf = UF.postscan Fold.sum UF.fromList + let unf = UF.postscanl Scanl.sum UF.fromList mList = scanl1 (+) ls in testUnfold unf ls mList @@ -479,7 +481,7 @@ mapM2 = $ \f list -> let fA = applyFun2 f :: [Int] -> Int -> Int fM (x, y) = modify (+ 1) >> return (fA x y) - unf = UF.mapM fM (UF.carry UF.fromList) + unf = UF.mapM fM (UF.carryInput UF.fromList) mList = Prelude.map (fA list) list in testUnfoldMD unf list 0 (length list) mList diff --git a/test/Streamly/Test/Prelude/Serial.hs b/test/Streamly/Test/Prelude/Serial.hs index 945759dfb8..8c09d7c448 100644 --- a/test/Streamly/Test/Prelude/Serial.hs +++ b/test/Streamly/Test/Prelude/Serial.hs @@ -494,7 +494,7 @@ unfold :: Property unfold = monadicIO $ do a <- pick $ choose (0, max_length `div` 2) b <- pick $ choose (0, max_length) - let unf = UF.second b UF.enumerateFromToIntegral + let unf = UF.supplySecond b UF.enumerateFromToIntegral ls <- toList $ S.unfold unf a return $ ls == [a..b]