on master help sign in
Move Fold Step to a separate module
commit9738b4b73e042e947b8b92e3a1b3cc5d86f1a36f authorHarendra Kumar <harendra@composewell.com> dateFri 8 Oct 2021, 17:18 (5 years ago) parentf3c31f0
3 files changed+87−65
src/Streamly/Internal/Data/Fold/Step.hs+83 src/Streamly/Internal/Data/Fold/Type.hs+3−65 streamly.cabal+1
src/Streamly/Internal/Data/Fold/Step.hsnew file+83
@@ -0,0 +1,83 @@
1+-- |
2+-- Module : Streamly.Internal.Data.Fold.Step
3+-- Copyright : (c) 2019 Composewell Technologies
4+-- License : BSD3
5+-- Maintainer : streamly@composewell.com
6+-- Stability : experimental
7+-- Portability : GHC
8+--
9+module Streamly.Internal.Data.Fold.Step
10+ (
11+ -- * Types
12+ Step (..)
13+
14+ , mapMStep
15+ , chainStepM
16+ )
17+where
18+
19+import Data.Bifunctor (Bifunctor(..))
20+import Fusion.Plugin.Types (Fuse(..))
21+
22+------------------------------------------------------------------------------
23+-- Step of a fold
24+------------------------------------------------------------------------------
25+
26+-- The Step functor around b allows expressing early termination like a right
27+-- fold. Traditional list right folds use function composition and laziness to
28+-- terminate early whereas we use data constructors. It allows stream fusion in
29+-- contrast to the foldr/build fusion when composing with functions.
30+
31+-- | Represents the result of the @step@ of a 'Fold'. 'Partial' returns an
32+-- intermediate state of the fold, the fold step can be called again with the
33+-- state or the driver can use @extract@ on the state to get the result out.
34+-- 'Done' returns the final result and the fold cannot be driven further.
35+--
36+-- /Pre-release/
37+--
38+{-# ANN type Step Fuse #-}
39+data Step s b
40+ = Partial !s
41+ | Done !b
42+
43+-- | 'first' maps over 'Partial' and 'second' maps over 'Done'.
44+--
45+instance Bifunctor Step where
46+ {-# INLINE bimap #-}
47+ bimap f _ (Partial a) = Partial (f a)
48+ bimap _ g (Done b) = Done (g b)
49+
50+ {-# INLINE first #-}
51+ first f (Partial a) = Partial (f a)
52+ first _ (Done x) = Done x
53+
54+ {-# INLINE second #-}
55+ second _ (Partial x) = Partial x
56+ second f (Done a) = Done (f a)
57+
58+-- | 'fmap' maps over 'Done'.
59+--
60+-- @
61+-- fmap = 'second'
62+-- @
63+--
64+instance Functor (Step s) where
65+ {-# INLINE fmap #-}
66+ fmap = second
67+
68+-- | Map a monadic function over the result @b@ in @Step s b@.
69+--
70+-- /Internal/
71+{-# INLINE mapMStep #-}
72+mapMStep :: Applicative m => (a -> m b) -> Step s a -> m (Step s b)
73+mapMStep f res =
74+ case res of
75+ Partial s -> pure $ Partial s
76+ Done b -> Done <$> f b
77+
78+-- | If 'Partial' then map the state, if 'Done' then call the next step.
79+{-# INLINE chainStepM #-}
80+chainStepM :: Applicative m =>
81+ (s1 -> m s2) -> (a -> m (Step s2 b)) -> Step s1 a -> m (Step s2 b)
82+chainStepM f _ (Partial s) = Partial <$> f s
83+chainStepM _ g (Done b) = g b
src/Streamly/Internal/Data/Fold/Type.hs+3−65
@@ -269,6 +269,7 @@ import Control.Monad ((>=>))
269269import Data.Bifunctor (Bifunctor(..))
270270import Data.Maybe (isJust, fromJust)
271271import Fusion.Plugin.Types (Fuse(..))
272+import Streamly.Internal.Data.Fold.Step (Step(..), mapMStep, chainStepM)
272273import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
273274import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3'(..))
274275import Streamly.Internal.Data.Consumer.Type (Consumer(..))
@@ -291,69 +292,6 @@ import Prelude hiding (concatMap, filter, foldr, map, take)
291292-- >>> import qualified Streamly.Internal.Data.Stream.IsStream as Stream
292293-- >>> import qualified Streamly.Internal.Data.Stream.StreamK as StreamK
293294
294−------------------------------------------------------------------------------
295−-- Step of a fold
296−------------------------------------------------------------------------------
297−
298−-- The Step functor around b allows expressing early termination like a right
299−-- fold. Traditional list right folds use function composition and laziness to
300−-- terminate early whereas we use data constructors. It allows stream fusion in
301−-- contrast to the foldr/build fusion when composing with functions.
302−
303−-- | Represents the result of the @step@ of a 'Fold'. 'Partial' returns an
304−-- intermediate state of the fold, the fold step can be called again with the
305−-- state or the driver can use @extract@ on the state to get the result out.
306−-- 'Done' returns the final result and the fold cannot be driven further.
307−--
308−-- /Pre-release/
309−--
310−{-# ANN type Step Fuse #-}
311−data Step s b
312− = Partial !s
313− | Done !b
314−
315−-- | 'first' maps over 'Partial' and 'second' maps over 'Done'.
316−--
317−instance Bifunctor Step where
318− {-# INLINE bimap #-}
319− bimap f _ (Partial a) = Partial (f a)
320− bimap _ g (Done b) = Done (g b)
321−
322− {-# INLINE first #-}
323− first f (Partial a) = Partial (f a)
324− first _ (Done x) = Done x
325−
326− {-# INLINE second #-}
327− second _ (Partial x) = Partial x
328− second f (Done a) = Done (f a)
329−
330−-- | 'fmap' maps over 'Done'.
331−--
332−-- @
333−-- fmap = 'second'
334−-- @
335−--
336−instance Functor (Step s) where
337− {-# INLINE fmap #-}
338− fmap = second
339−
340−-- | Map a monadic function over the result @b@ in @Step s b@.
341−--
342−-- /Internal/
343−{-# INLINE mapMStep #-}
344−mapMStep :: Applicative m => (a -> m b) -> Step s a -> m (Step s b)
345−mapMStep f res =
346− case res of
347− Partial s -> pure $ Partial s
348− Done b -> Done <$> f b
349−
350−-- | If 'Partial' then map the state, if 'Done' then call the next step.
351−{-# INLINE chainStepM #-}
352−chainStepM :: Applicative m =>
353− (s1 -> m s2) -> (a -> m (Step s2 b)) -> Step s1 a -> m (Step s2 b)
354−chainStepM f _ (Partial s) = Partial <$> f s
355−chainStepM _ g (Done b) = g b
356−
357295------------------------------------------------------------------------------
358296-- The Fold type
359297------------------------------------------------------------------------------
@@ -668,7 +606,7 @@ fromPure b = Fold undefined (pure $ Done b) pure
668606fromEffect :: Applicative m => m b -> Fold m a b
669607fromEffect b = Fold undefined (Done <$> b) pure
670608
671−{-# ANN type Step Fuse #-}
609+{-# ANN type SeqFoldState Fuse #-}
672610data SeqFoldState sl f sr = SeqFoldL !sl | SeqFoldR !f !sr
673611
674612-- | Sequential fold application. Apply two folds sequentially to an input
@@ -723,7 +661,7 @@ serialWith func (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
723661 Partial sR -> extractR sR
724662 Done rR -> return rR
725663
726−{-# ANN type Step Fuse #-}
664+{-# ANN type SeqFoldState_ Fuse #-}
727665data SeqFoldState_ sl sr = SeqFoldL_ !sl | SeqFoldR_ !sr
728666
729667-- | Same as applicative '*>'. Run two folds serially one after the other
streamly.cabal+1
@@ -385,6 +385,7 @@ library
385385 , Streamly.Internal.Data.SVar.Pull
386386 , Streamly.Internal.Data.SVar
387387 , Streamly.Internal.Data.Stream.StreamK.Type
388+ , Streamly.Internal.Data.Fold.Step
388389 , Streamly.Internal.Data.Consumer.Type
389390 , Streamly.Internal.Data.Fold.Type
390391 , Streamly.Internal.Data.Stream.StreamD.Step