@@ -8,6 +8,34 @@
88-- Stability : experimental
99-- Portability : GHC
1010--
11+-- = Unfolds and Streams
12+--
13+-- An 'Unfold' type is the same as the direct style 'Stream' type except that
14+-- it uses an inject function to determine the initial state of the stream
15+-- based on an input. A stream is a special case of Unfold when the static
16+-- input is unit or Void.
17+--
18+-- This allows an important optimization to occur in several cases, making the
19+-- 'Unfold' a more efficient abstraction. Consider the 'concatMap' and
20+-- 'concatUnfold' operations, the latter is more efficient. 'concatMap'
21+-- generates a new stream object from each element in the stream by applying
22+-- the supplied function to the element, the stream object includes the "step"
23+-- function as well as the initial "state" of the stream. Since the stream is
24+-- generated dynamically the compiler does not know the step function or the
25+-- state type statically at compile time, therefore, it cannot inline it. On
26+-- the other hand in case of 'concatUnfold' the compiler has visibility into
27+-- the unfold's state generation function, therefore, the compiler knows all
28+-- the types statically and it can inline the inject as well as the step
29+-- functions, generating efficient code. Essentially, the stream is not opaque
30+-- to the consumer in case of unfolds, the consumer knows how to generate the
31+-- stream from a seed using a known "inject" and "step" functions.
32+--
33+-- A Stream is like a data object whereas unfold is like a function. Being
34+-- function like, an Unfold is an instance of 'Category' and 'Arrow' type
35+-- classes.
36+--
37+-- = Unfolds and Folds
38+--
1139-- Streams forcing a closed control flow loop can be categorized under
1240-- two types, unfolds and folds, both of these are duals of each other.
1341--
@@ -149,15 +177,12 @@ import Control.Monad.Trans.Control (MonadBaseControl, liftBaseOp_)
149177import Data.IORef (newIORef, readIORef, mkWeakIORef, writeIORef)
150178import Data.Maybe (isNothing)
151179import Data.Void (Void)
152−import Fusion.Plugin.Types (Fuse(..))
153180import GHC.Types (SPEC(..))
154181import Streamly.Internal.Data.Fold.Types (Fold(..))
155182import Streamly.Internal.Data.IOFinalizer
156183 (newIOFinalizer, runIOFinalizer, clearingIOFinalizer)
157184import Streamly.Internal.Data.Stream.StreamD.Type (Stream(..), Step(..))
158185import Streamly.Internal.Data.Time.Clock (Clock(Monotonic), getTime)
159−import Streamly.Internal.Data.Unfold.Types
160− (Unfold(..), lmap, map, const, concatMapM)
161186import System.Mem (performMajorGC)
162187
163188import qualified Prelude
@@ -169,6 +194,7 @@ import qualified Streamly.Internal.Data.Stream.StreamK as K (uncons)
169194import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
170195
171196import Streamly.Internal.Data.SVar
197+import Streamly.Internal.Data.Unfold.Types
172198import Prelude
173199 hiding (concat, map, mapM, takeWhile, take, filter, const, zipWith
174200 , drop, dropWhile)
@@ -399,34 +425,6 @@ effect eff = Unfold step inject
399425 step True = eff >>= \r -> return $ Yield r False
400426 step False = return Stop
401427
402−-- XXX change it to yieldM or change yieldM in Prelude to singletonM
403−--
404−-- | Lift a monadic function into an unfold generating a singleton stream.
405−--
406−{-# INLINE singletonM #-}
407−singletonM :: Monad m => (a -> m b) -> Unfold m a b
408−singletonM f = Unfold step inject
409− where
410− inject x = return $ Just x
411− {-# INLINE_LATE step #-}
412− step (Just x) = f x >>= \r -> return $ Yield r Nothing
413− step Nothing = return Stop
414−
415−-- | Lift a pure function into an unfold generating a singleton stream.
416−--
417−{-# INLINE singleton #-}
418−singleton :: Monad m => (a -> b) -> Unfold m a b
419−singleton f = singletonM $ return . f
420−
421−-- | Identity unfold. Generates a singleton stream with the seed as the only
422−-- element in the stream.
423−--
424−-- > identity = singletonM return
425−--
426−{-# INLINE identity #-}
427−identity :: Monad m => Unfold m a a
428−identity = singletonM return
429−
430428-- | Convert a list of pure values to a 'Stream'
431429{-# INLINE_LATE fromList #-}
432430fromList :: Monad m => Unfold m [a] a
@@ -842,53 +840,6 @@ fromProducer = Unfold step (return . FromSVarRead)
842840-- Zipping
843841-------------------------------------------------------------------------------
844842
845−{-# INLINE_NORMAL zipWithM #-}
846−zipWithM :: Monad m
847− => (a -> b -> m c) -> Unfold m x a -> Unfold m y b -> Unfold m (x, y) c
848−zipWithM f (Unfold step1 inject1) (Unfold step2 inject2) = Unfold step inject
849−
850− where
851−
852− inject (x, y) = do
853− s1 <- inject1 x
854− s2 <- inject2 y
855− return (s1, s2, Nothing)
856−
857− {-# INLINE_LATE step #-}
858− step (s1, s2, Nothing) = do
859− r <- step1 s1
860− return $
861− case r of
862− Yield x s -> Skip (s, s2, Just x)
863− Skip s -> Skip (s, s2, Nothing)
864− Stop -> Stop
865−
866− step (s1, s2, Just x) = do
867− r <- step2 s2
868− case r of
869− Yield y s -> do
870− z <- f x y
871− return $ Yield z (s1, s, Nothing)
872− Skip s -> return $ Skip (s1, s, Just x)
873− Stop -> return Stop
874−
875−-- | Divide the input into two unfolds and then zip the outputs to a single
876−-- stream.
877−--
878−-- @
879−-- S.mapM_ print
880−-- $ S.concatUnfold (UF.zipWith (,) UF.identity (UF.singleton sqrt))
881−-- $ S.map (\x -> (x,x))
882−-- $ S.fromList [1..10]
883−-- @
884−--
885−-- /Internal/
886−--
887−{-# INLINE zipWith #-}
888−zipWith :: Monad m
889− => (a -> b -> c) -> Unfold m x a -> Unfold m y b -> Unfold m (x, y) c
890−zipWith f = zipWithM (\a b -> return (f a b))
891−
892843-- | Distribute the input to two unfolds and then zip the outputs to a single
893844-- stream.
894845--
@@ -907,39 +858,6 @@ teeZipWith f unf1 unf2 = lmap (\x -> (x,x)) $ zipWith f unf1 unf2
907858-- Nested
908859-------------------------------------------------------------------------------
909860
910−{-# ANN type ConcatState Fuse #-}
911−data ConcatState s1 s2 = ConcatOuter s1 | ConcatInner s1 s2
912−
913−-- | Apply the second unfold to each output element of the first unfold and
914−-- flatten the output in a single stream.
915−--
916−-- /Internal/
917−--
918−{-# INLINE_NORMAL concat #-}
919−concat :: Monad m => Unfold m a b -> Unfold m b c -> Unfold m a c
920−concat (Unfold step1 inject1) (Unfold step2 inject2) = Unfold step inject
921− where
922− inject x = do
923− s <- inject1 x
924− return $ ConcatOuter s
925−
926− {-# INLINE_LATE step #-}
927− step (ConcatOuter st) = do
928− r <- step1 st
929− case r of
930− Yield x s -> do
931− innerSt <- inject2 x
932− return $ Skip (ConcatInner s innerSt)
933− Skip s -> return $ Skip (ConcatOuter s)
934− Stop -> return Stop
935−
936− step (ConcatInner ost ist) = do
937− r <- step2 ist
938− return $ case r of
939− Yield x s -> Yield x (ConcatInner ost s)
940− Skip s -> Skip (ConcatInner ost s)
941− Stop -> Skip (ConcatOuter ost)
942−
943861data OuterProductState s1 s2 sy x y =
944862 OuterProductOuter s1 y | OuterProductInner s1 sy s2 x
945863