{-# OPTIONS_GHC -Wno-name-shadowing #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE LinearTypes #-} {-# LANGUAGE QualifiedDo #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} module Streaming.Linear ( -- $stream module Streaming.Internal.Type -- * Constructing a 'Stream' on a given functor , yields , effect , wrap , replicates , replicatesM , unfold , untilJust , streamBuild , delays -- * Transforming streams , maps , mapsPost , mapsM , mapsMPost , mapped , mappedPost , hoistUnexposed , groups -- * Inspecting a stream , inspect -- * Splitting and joining 'Stream's , splitsAt , chunksOf , concats , intercalates -- * Zipping, unzipping, separating and unseparating streams , unzips , separate , unseparate , decompose , expand , expandPost -- * Eliminating a 'Stream' , mapsM_ , run , streamFold , iterTM , iterT , destroy ) where import Streaming.Internal.Type import Streaming.Internal.Process (destroyExposed) import Data.Functor.Sum import Data.Functor.Compose import qualified Streaming.Prelude.Linear as Stream import System.IO.Linear import Prelude.Linear (($), (.), (&)) import Prelude (Ordering(..), Ord(..), Num(..), Int, Either(..), Double, Maybe(..), fromInteger) import qualified Prelude import qualified Control.Functor.Linear as Control import qualified Data.Functor.Linear as Data import Data.Unrestricted.Linear import Control.Concurrent (threadDelay) import GHC.Stack {- $stream The 'Stream' data type is an effectful series of steps with some payload value at the bottom. The steps are represented with functors. The effects are represented with some /control/ monad. (Control monads must be bound to exactly once; see the documentation in to learn more about control monads, control applicatives and control functors.) In words, a @Stream f m r@ is either a payload of type @r@, or a step of type @f (Stream f m r)@ or an effect of type @m (Stream f m r)@ where @f@ is a @Control.Functor@ and @m@ is a @Control.Monad@. This module exports combinators that pertain to this general case. Some of these are quite abstract and pervade any use of the library, e.g. > maps :: (forall x . f x %1-> g x) -> Stream f m r %1-> Stream g m r > mapped :: (forall x. f x %1-> m (g x)) -> Stream f m r %1-> Stream g m r > concats :: Stream (Stream f m) m r %1-> Stream f m r (assuming here and thoughout that @m@ or @n@ satisfies a @Control.Monad@ constraint, and @f@ or @g@ a @Control.Functor@ constraint). Others are surprisingly determinate in content: > chunksOf :: Int -> Stream f m r %1-> Stream (Stream f m) m r > splitsAt :: Int -> Stream f m r %1-> Stream f m (Stream f m r) > intercalates :: Stream f m () -> Stream (Stream f m) m r %1-> Stream f m r > unzips :: Stream (Compose f g) m r %1-> Stream f (Stream g m) r > separate :: Stream (Sum f g) m r -> Stream f (Stream g m) r -- cp. partitionEithers > unseparate :: Stream f (Stream g) m r -> Stream (Sum f g) m r > groups :: Stream (Sum f g) m r %1-> Stream (Sum (Stream f m) (Stream g m)) m r One way to see that /any/ streaming library needs some such general type is that it is required to represent the segmentation of a stream, and to express the equivalents of @Prelude/Data.List@ combinators that involve 'lists of lists' and the like. See for example this on the correct expression of a streaming \'lines\' function. The module @Streaming.Prelude@ exports combinators relating to > Stream (Of a) m r where @Of a r = !a :> r@ is a left-strict pair. This expresses the concept of a 'Producer' or 'Source' or 'Generator' and easily inter-operates with types with such names in e.g. 'conduit', 'iostreams' and 'pipes'. -} -- # Constructing a 'Stream' on a given functor ------------------------------------------------------------------------------- -- Remark. By default we require `Control.Monad` and `Control.Functor` -- instances for the `m` and `f` in a `Stream f m r` since these allow the -- stream to have a `Control.Monad` instance {-| @yields@ is like @lift@ for items in the streamed functor. It makes a singleton or one-layer succession. > lift :: (Control.Monad m, Control.Functor f) => m r %1-> Stream f m r > yields :: (Control.Monad m, Control.Functor f) => f r %1-> Stream f m r Viewed in another light, it is like a functor-general version of @yield@: > S.yield a = yields (a :> ()) -} yields :: (Control.Monad m, Control.Functor f) => f r %1-> Stream f m r yields fr = Step $ Control.fmap Return fr {-# INLINE yields #-} -- Note: This must consume its input linearly since it must bind to a -- `Control.Monad`. {- | Wrap an effect that returns a stream > effect = join . lift -} effect :: (Control.Monad m, Control.Functor f) => m (Stream f m r) %1-> Stream f m r effect = Effect {-# INLINE effect #-} {-| Wrap a new layer of a stream. So, e.g. > S.cons :: Control.Monad m => a -> Stream (Of a) m r %1-> Stream (Of a) m r > S.cons a str = wrap (a :> str) and, recursively: > S.each' :: Control.Monad m => [a] -> Stream (Of a) m () > S.each' = foldr (\a b -> wrap (a :> b)) (return ()) The two operations > wrap :: (Control.Monad m, Control.Functor f) => > f (Stream f m r) %1-> Stream f m r > effect :: (Control.Monad m, Control.Functor f) => > m (Stream f m r) %1-> Stream f m r are fundamental. We can define the parallel operations @yields@ and @lift@ in terms of them > yields :: (Control.Monad m, Control.Functor f) => f r %1-> Stream f m r > yields = wrap . Control.fmap Control.return > lift :: (Control.Monad m, Control.Functor f) => m r %1-> Stream f m r > lift = effect . Control.fmap Control.return -} wrap :: (Control.Monad m, Control.Functor f) => f (Stream f m r) %1-> Stream f m r wrap = Step {-# INLINE wrap #-} {- | Repeat a functorial layer, command or instruction a fixed number of times. -} replicates :: (HasCallStack, Control.Monad m, Control.Functor f) => Int -> f () -> Stream f m () replicates n f = replicates' n f where replicates' :: (HasCallStack, Control.Monad m, Control.Functor f) => Int -> f () -> Stream f m () replicates' n f = case compare n 0 of LT -> Prelude.error "replicates called with negative integer" EQ -> Return () GT -> Step $ Control.fmap (\() -> replicates (n-1) f) f {-# INLINE replicates #-} -- | @replicatesM n@ repeats an effect containing a functorial layer, command -- or instruction @n@ times. replicatesM :: forall f m . (Control.Monad m, Control.Functor f) => Int -> m (f ()) -> Stream f m () replicatesM = loop where loop :: Int -> m (f ()) -> Stream f m () loop n mfstep | n <= 0 = Return () | Prelude.otherwise = Effect $ Control.fmap (Step . Control.fmap (\() -> loop (n-1) mfstep)) mfstep {-# INLINABLE replicatesM #-} unfold :: (Control.Monad m, Control.Functor f) => (s %1-> m (Either r (f s))) -> s %1-> Stream f m r unfold step state = unfold' step state where unfold' :: (Control.Monad m, Control.Functor f) => (s %1-> m (Either r (f s))) -> s %1-> Stream f m r unfold' step state = Effect $ Control.do either <- step state either & \case Left r -> Control.return $ Return r Right (fs) -> Control.return $ Step $ Control.fmap (unfold step) fs {-# INLINABLE unfold #-} -- Note. To keep restrictions minimal, we use the `Data.Applicative` -- instance. untilJust :: forall f m r . (Control.Monad m, Data.Applicative f) => m (Maybe r) -> Stream f m r untilJust action = loop where loop :: Stream f m r loop = Effect $ Control.do maybeVal <- action maybeVal & \case Nothing -> Control.return $ Step $ Data.pure loop Just r -> Control.return $ Return r {-# INLINABLE untilJust #-} -- Remark. The linear church encoding of streams has linear -- return, effect and step functions. {- | Reflect a church-encoded stream; cp. @GHC.Exts.build@ > streamFold return_ effect_ step_ (streamBuild psi) = psi return_ effect_ step_ -} streamBuild :: (forall b. (r %1-> b) -> (m b %1-> b) -> (f b %1-> b) -> b) -> Stream f m r streamBuild = \phi -> phi Return Effect Step {-# INLINE streamBuild #-} -- Note. To keep requirements minimal, we use the `Data.Applicative` -- instance instead of the `Control.Applicative` instance. delays :: forall f r . (Data.Applicative f) => Double -> Stream f IO r delays seconds = loop where loop :: Stream f IO r loop = Effect $ Control.do let delay = fromInteger (Prelude.truncate (1000000 * seconds)) () <- fromSystemIO $ threadDelay delay Control.return $ Step $ Data.pure loop {-# INLINABLE delays #-} -- # Transforming streams ------------------------------------------------------------------------------- {- | Map layers of one functor to another with a transformation. > maps id = id > maps f . maps g = maps (f . g) -} maps :: forall f g m r . (Control.Monad m, Control.Functor f) => (forall x . f x %1-> g x) -> Stream f m r %1-> Stream g m r maps = Stream.maps {-# INLINE maps #-} {- | Map layers of one functor to another with a transformation. > mapsPost id = id > mapsPost f . mapsPost g = mapsPost (f . g) > mapsPost f = maps f @mapsPost@ is essentially the same as 'maps', but it imposes a @Control.Functor@ constraint on its target functor rather than its source functor. It should be preferred if @Control.fmap@ is cheaper for the target functor than for the source functor. -} mapsPost :: forall m f g r. (Control.Monad m, Control.Functor g) => (forall x. f x %1-> g x) -> Stream f m r %1-> Stream g m r mapsPost = Stream.mapsPost {-# INLINE mapsPost #-} -- Note. The transformation function must be linear so that the stream -- held inside a control functor is used linearly. {- | Map layers of one functor to another with a transformation involving the base monad. 'maps' is more fundamental than @mapsM@, which is best understood as a convenience for effecting this frequent composition: > mapsM phi = decompose . maps (Compose . phi) The streaming prelude exports the same function under the better name @mapped@, which overlaps with the lens libraries. -} mapsM :: forall f g m r . (Control.Monad m, Control.Functor f) => (forall x. f x %1-> m (g x)) -> Stream f m r %1-> Stream g m r mapsM transform = loop where loop :: Stream f m r %1-> Stream g m r loop stream = stream & \case Return r -> Return r Step f -> Effect $ Control.fmap Step $ transform $ Control.fmap loop f Effect m -> Effect $ Control.fmap loop m {-# INLINE mapsM #-} {- | Map layers of one functor to another with a transformation involving the base monad. @mapsMPost@ is essentially the same as 'mapsM', but it imposes a @Control.Functor@ constraint on its target functor rather than its source functor. It should be preferred if @Control.fmap@ is cheaper for the target functor than for the source functor. @mapsPost@ is more fundamental than @mapsMPost@, which is best understood as a convenience for effecting this frequent composition: > mapsMPost phi = decompose . mapsPost (Compose . phi) The streaming prelude exports the same function under the better name @mappedPost@, which overlaps with the lens libraries. -} mapsMPost :: forall m f g r. (Control.Monad m, Control.Functor g) => (forall x. f x %1-> m (g x)) -> Stream f m r %1-> Stream g m r mapsMPost = Stream.mapsMPost {-# INLINE mapsMPost #-} {- | Map layers of one functor to another with a transformation involving the base monad. This could be trivial, e.g. > let noteBeginning text x = (fromSystemIO (System.putStrLn text)) Control.>> (Control.return x) this is completely functor-general @maps@ and @mapped@ obey these rules: > maps id = id > mapped return = id > maps f . maps g = maps (f . g) > mapped f . mapped g = mapped (f <=< g) > maps f . mapped g = mapped (fmap f . g) > mapped f . maps g = mapped (f <=< fmap g) @maps@ is more fundamental than @mapped@, which is best understood as a convenience for effecting this frequent composition: > mapped phi = decompose . maps (Compose . phi) -} mapped :: forall f g m r . (Control.Monad m, Control.Functor f) => (forall x. f x %1-> m (g x)) -> Stream f m r %1-> Stream g m r mapped = mapsM {-# INLINE mapped #-} {-| A version of 'mapped' that imposes a @Control.Functor@ constraint on the target functor rather than the source functor. This version should be preferred if @Control.fmap@ on the target functor is cheaper. -} mappedPost :: forall m f g r. (Control.Monad m, Control.Functor g) => (forall x. f x %1-> m (g x)) -> Stream f m r %1-> Stream g m r mappedPost = mapsMPost {-# INLINE mappedPost #-} -- | A less-efficient version of 'hoist' that works properly even when its -- argument is not a monad morphism. hoistUnexposed :: forall f m n r. (Control.Monad m, Control.Functor f) => (forall a. m a %1-> n a) -> Stream f m r %1-> Stream f n r hoistUnexposed trans = loop where loop :: Stream f m r %1-> Stream f n r loop = Effect . trans . inspectC (Control.return . Return) (Control.return . Step . Control.fmap loop) {-# INLINABLE hoistUnexposed #-} -- A version of 'inspect' that takes explicit continuations. -- Note that due to the linear constructors of 'Stream', these continuations -- are linear. inspectC :: forall f m r a. Control.Monad m => (r %1-> m a) -> (f (Stream f m r) %1-> m a) -> Stream f m r %1-> m a inspectC f g = loop where loop :: Stream f m r %1-> m a loop (Return r) = f r loop (Step x) = g x loop (Effect m) = m Control.>>= loop {-# INLINE inspectC #-} {-| Group layers in an alternating stream into adjoining sub-streams of one type or another. -} groups :: forall f g m r . (Control.Monad m, Control.Functor f, Control.Functor g) => Stream (Sum f g) m r %1-> Stream (Sum (Stream f m) (Stream g m)) m r groups = loop where loop :: Stream (Sum f g) m r %1-> Stream (Sum (Stream f m) (Stream g m)) m r loop str = Control.do e <- Control.lift $ inspect str e & \case Left r -> Control.return r Right ostr -> ostr & \case InR gstr -> Step $ InR $ Control.fmap loop $ cleanR (Step (InR gstr)) InL fstr -> Step $ InL $ Control.fmap loop $ cleanL (Step (InL fstr)) cleanL :: Stream (Sum f g) m r %1-> Stream f m (Stream (Sum f g) m r) cleanL = go where go :: Stream (Sum f g) m r %1-> Stream f m (Stream (Sum f g) m r) go s = Control.do e <- Control.lift $ inspect s e & \case Left r -> Control.return $ Control.return r Right (InL fstr) -> Step $ Control.fmap go fstr Right (InR gstr) -> Control.return $ Step (InR gstr) cleanR :: Stream (Sum f g) m r %1-> Stream g m (Stream (Sum f g) m r) cleanR = go where go :: Stream (Sum f g) m r %1-> Stream g m (Stream (Sum f g) m r) go s = Control.do e <- Control.lift $ inspect s e & \case Left r -> Control.return $ Control.return r Right (InL fstr) -> Control.return $ Step (InL fstr) Right (InR gstr) -> Step$ Control.fmap go gstr {-# INLINABLE groups #-} -- # Inspecting a Stream ------------------------------------------------------------------------------- {-| Inspect the first stage of a freely layered sequence. Compare @Pipes.next@ and the replica @Streaming.Prelude.next@. This is the 'uncons' for the general 'unfold'. > unfold inspect = id > Streaming.Prelude.unfoldr StreamingPrelude.next = id -} inspect :: forall f m r . Control.Monad m => Stream f m r %1-> m (Either r (f (Stream f m r))) inspect = loop where loop :: Stream f m r %1-> m (Either r (f (Stream f m r))) loop stream = stream & \case Return r -> Control.return (Left r) Effect m -> m Control.>>= loop Step fs -> Control.return (Right fs) {-# INLINABLE inspect #-} -- # Splitting and joining 'Stream's ------------------------------------------------------------------------------- {-| Split a succession of layers after some number, returning a streaming or effectful pair. \>\>\> rest <- S.print $ S.splitAt 1 $ each' [1..3] 1 \>\>\> S.print rest 2 3 > splitAt 0 = return > (\stream -> splitAt n stream >>= splitAt m) = splitAt (m+n) Thus, e.g. \>\>\> rest <- S.print $ (\s -> splitsAt 2 s >>= splitsAt 2) each' [1..5] 1 2 3 4 \>\>\> S.print rest 5 -} splitsAt :: forall f m r . (HasCallStack, Control.Monad m, Control.Functor f) => Int -> Stream f m r %1-> Stream f m (Stream f m r) splitsAt n stream = loop n stream where loop :: Int -> Stream f m r %1-> Stream f m (Stream f m r) loop n stream = case compare n 0 of LT -> Prelude.error "splitsAt called with negative index" $ stream EQ -> Return stream GT -> stream & \case Return r -> Return $ Return r Effect m -> Effect $ Control.fmap (loop n) m Step f -> Step $ Control.fmap (loop (n-1)) f {-# INLINABLE splitsAt #-} {-| Break a stream into substreams each with n functorial layers. \>\>\> S.print $ mapped S.sum $ chunksOf 2 $ each' [1,1,1,1,1] 2 2 1 -} chunksOf :: forall f m r . (HasCallStack, Control.Monad m, Control.Functor f) => Int -> Stream f m r %1-> Stream (Stream f m) m r chunksOf n stream = loop n stream where loop :: Int -> Stream f m r %1-> Stream (Stream f m) m r loop _ (Return r) = Return r loop n stream = Step $ Control.fmap (loop n) $ splitsAt n stream {-# INLINABLE chunksOf #-} {-| Dissolves the segmentation into layers of @Stream f m@ layers. -} concats :: forall f m r . (Control.Monad m, Control.Functor f) => Stream (Stream f m) m r %1-> Stream f m r concats = loop where loop :: Stream (Stream f m) m r %1-> Stream f m r loop stream = stream & \case Return r -> Return r Effect m -> Effect $ Control.fmap loop m Step f -> Control.do rest <- Control.fmap loop f rest {-# INLINE concats #-} -- Note. To keep the monad of the stream a control monad, we need -- `(t m)` to be a control monad, and hence `t` to be a control -- monad transformer. {-| Interpolate a layer at each segment. This specializes to e.g. > intercalates :: Stream f m () -> Stream (Stream f m) m r %1-> Stream f m r -} intercalates :: forall t m r x . (Control.Monad m, Control.Monad (t m), Control.MonadTrans t, Consumable x) => t m x -> Stream (t m) m r %1-> t m r intercalates sep = go0 where go0 :: Stream (t m) m r %1-> t m r go0 f = f & \case Return r -> Control.return r Effect m -> Control.lift m Control.>>= go0 Step fstr -> Control.do f' <- fstr go1 f' go1 :: Stream (t m) m r %1-> t m r go1 f = f & \case Return r -> Control.return r Effect m -> Control.lift m Control.>>= go1 Step fstr -> Control.do x <- sep Control.return $ consume x f' <- fstr go1 f' {-# INLINABLE intercalates #-} -- # Zipping, unzipping, separating and unseparating streams ------------------------------------------------------------------------------- unzips :: forall f g m r . (Control.Monad m, Control.Functor f, Control.Functor g) => Stream (Compose f g) m r %1-> Stream f (Stream g m) r unzips str = destroyExposed str (\(Compose fgstr) -> Step (Control.fmap (Effect . yields) fgstr)) (Effect . Control.lift) Return {-# INLINABLE unzips #-} {-| Given a stream on a sum of functors, make it a stream on the left functor, with the streaming on the other functor as the governing monad. This is useful for acting on one or the other functor with a fold, leaving the other material for another treatment. It generalizes 'Data.Either.partitionEithers', but actually streams properly. \>\>\> let odd_even = S.maps (S.distinguish even) $ S.each' [1..10::Int] \>\>\> :t separate odd_even separate odd_even :: Monad m => Stream (Of Int) (Stream (Of Int) m) () Now, for example, it is convenient to fold on the left and right values separately: \>\>\> S.toList $ S.toList $ separate odd_even [2,4,6,8,10] :> ([1,3,5,7,9] :> ()) Or we can write them to separate files or whatever: \>\>\> S.writeFile "even.txt" . S.show $ S.writeFile "odd.txt" . S.show $ S.separate odd_even \>\>\> :! cat even.txt 2 4 6 8 10 \>\>\> :! cat odd.txt 1 3 5 7 9 Of course, in the special case of @Stream (Of a) m r@, we can achieve the above effects more simply by using 'Streaming.Prelude.copy' \>\>\> S.toList . S.filter even $ S.toList . S.filter odd $ S.copy $ each [1..10::Int] [2,4,6,8,10] :> ([1,3,5,7,9] :> ()) But 'separate' and 'unseparate' are functor-general. -} separate :: forall f g m r . (Control.Monad m, Control.Functor f, Control.Functor g) => Stream (Sum f g) m r -> Stream f (Stream g m) r separate str = destroyExposed str construct (Effect . Control.lift) Return where construct :: Sum f g (Stream f (Stream g m) r) %1-> Stream f (Stream g m) r construct (InL fss) = Step fss construct (InR gss) = Effect (yields gss) {-# INLINABLE separate #-} unseparate :: (Control.Monad m, Control.Functor f, Control.Functor g) => Stream f (Stream g m) r -> Stream (Sum f g) m r unseparate str = destroyExposed str (Step . InL) (Control.join . maps InR) Return {-# INLINABLE unseparate #-} {-| Rearrange a succession of layers of the form @Compose m (f x)@. we could as well define @decompose@ by @mapsM@: > decompose = mapped getCompose but @mapped@ is best understood as: > mapped phi = decompose . maps (Compose . phi) since @maps@ and @hoist@ are the really fundamental operations that preserve the shape of the stream: > maps :: (Control.Monad m, Control.Functor f) => (forall x. f x %1-> g x) -> Stream f m r %1-> Stream g m r > hoist :: (Control.Monad m, Control.Functor f) => (forall a. m a %1-> n a) -> Stream f m r %1-> Stream f n r -} decompose :: forall f m r . (Control.Monad m, Control.Functor f) => Stream (Compose m f) m r %1-> Stream f m r decompose = loop where loop :: Stream (Compose m f) m r %1-> Stream f m r loop stream = stream & \case Return r -> Return r Effect m -> Effect $ Control.fmap loop m Step (Compose mfs) -> Effect $ Control.do fstream <- mfs Control.return $ Step (Control.fmap loop fstream) {-# INLINABLE decompose #-} -- Note. For 'loop' to recurse over functoral steps, it must be a -- linear function, and hence, `ext` must be linear in its second argument. -- Further, the first argument of `ext` ought to be a linear function, -- because it is typically applied to the input stream in `ext`, and hence -- should be linear. -- | If 'Of' had a @Comonad@ instance, then we'd have -- -- @copy = expand extend@ -- -- See 'expandPost' for a version that requires a @Control.Functor g@ -- instance instead. expand :: forall f m r g h . (Control.Monad m, Control.Functor f) => (forall a b. (g a %1-> b) -> f a %1-> h b) -> Stream f m r %1-> Stream g (Stream h m) r expand ext = loop where loop :: Stream f m r %1-> Stream g (Stream h m) r loop (Return r) = Return r loop (Step f) = Effect $ Step $ ext (Return . Step) (Control.fmap loop f) loop (Effect m) = Effect $ Effect $ Control.fmap (Return . loop) m {-# INLINABLE expand #-} -- See note on 'expand'. -- | If 'Of' had a @Comonad@ instance, then we'd have -- -- @copy = expandPost extend@ -- -- See 'expand' for a version that requires a @Control.Functor f@ instance -- instead. expandPost :: forall f m r g h . (Control.Monad m, Control.Functor g) => (forall a b. (g a %1-> b) -> f a %1-> h b) -> Stream f m r %1-> Stream g (Stream h m) r expandPost ext = loop where loop :: Stream f m r %1-> Stream g (Stream h m) r loop (Return r) = Return r loop (Step f) = Effect $ Step $ ext (Return . Step . Control.fmap loop) f loop (Effect m) = Effect $ Effect $ Control.fmap (Return . loop) m {-# INLINABLE expandPost #-} -- # Eliminating a 'Stream' ------------------------------------------------------------------------------- -- Note. Since the functor step is held linearly in the -- 'Stream' datatype, the first argument must be a linear function -- in order to linearly consume the 'Step' case of a stream. {-| Map each layer to an effect, and run them all. -} mapsM_ :: (Control.Functor f, Control.Monad m) => (forall x . f x %1-> m x) -> Stream f m r %1-> m r mapsM_ f = run . maps f {-# INLINE mapsM_ #-} {-| Run the effects in a stream that merely layers effects. -} run :: Control.Monad m => Stream m m r %1-> m r run = loop where loop :: Control.Monad m => Stream m m r %1-> m r loop stream = stream & \case Return r -> Control.return r Effect m -> m Control.>>= loop Step mrest -> mrest Control.>>= loop {-# INLINABLE run #-} {-| 'streamFold' reorders the arguments of 'destroy' to be more akin to @foldr@ It is more convenient to query in ghci to figure out what kind of \'algebra\' you need to write. \>\>\> :t streamFold Control.return Control.join (Control.Monad m, Control.Functor f) => (f (m a) %1-> m a) -> Stream f m a %1-> m a -- iterT \>\>\> :t streamFold Control.return (Control.join . Control.lift) (Control.Monad m, Control.Monad (t m), Control.Functor f, Control.MonadTrans t) => (f (t m a) %1-> t m a) -> Stream f m a %1-> t m a -- iterTM \>\>\> :t streamFold Control.return effect (Control.Monad m, Control.Functor f, Control.Functor g) => (f (Stream g m r) %1-> Stream g m r) -> Stream f m r %1-> Stream g m r \>\>\> :t \f -> streamFold Control.return effect (wrap . f) (Control.Monad m, Control.Functor f, Control.Functor g) => (f (Stream g m a) %1-> g (Stream g m a)) -> Stream f m a %1-> Stream g m a -- maps \>\>\> :t \f -> streamFold Control.return effect (effect . Control.fmap wrap . f) (Control.Monad m, Control.Functor f, Control.Functor g) => (f (Stream g m a) %1-> m (g (Stream g m a))) -> Stream f m a %1-> Stream g m a -- mapped @ streamFold done eff construct = eff . iterT (Control.return . construct . Control.fmap eff) . Control.fmap done @ -} streamFold :: (Control.Functor f, Control.Monad m) => (r %1-> b) -> (m b %1-> b) -> (f b %1-> b) -> Stream f m r %1-> b streamFold done theEffect construct stream = destroy stream construct theEffect done {-# INLINE streamFold #-} {-| Specialized fold following the usage of @Control.Monad.Trans.Free@ > iterT alg = streamFold Control.return Control.join alg > iterT alg = runIdentityT . iterTM (IdentityT . alg . Control.fmap runIdentityT) -} iterT :: (Control.Functor f, Control.Monad m) => (f (m a) %1-> m a) -> Stream f m a %1-> m a iterT out stream = destroyExposed stream out Control.join Control.return {-# INLINE iterT #-} {-| Specialized fold following the usage of @Control.Monad.Trans.Free@ > iterTM alg = streamFold Control.return (Control.join . Control.lift) > iterTM alg = iterT alg . hoist Control.lift -} iterTM :: ( Control.Functor f, Control.Monad m , Control.MonadTrans t, Control.Monad (t m)) => (f (t m a) %1-> t m a) -> Stream f m a %1-> t m a iterTM out stream = destroyExposed stream out (Control.join . Control.lift) Control.return {-# INLINE iterTM #-} -- Note. 'destroy' needs to use linear functions in its church encoding -- to consume the stream linearly. {-| Map a stream to its church encoding; compare @Data.List.foldr@. 'destroyExposed' may be more efficient in some cases when applicable, but it is less safe. @ destroy s construct eff done = eff . iterT (Control.return . construct . Control.fmap eff) . Control.fmap done $ s @ -} destroy :: forall f m r b . (Control.Functor f, Control.Monad m) => Stream f m r %1-> (f b %1-> b) -> (m b %1-> b) -> (r %1-> b) -> b destroy stream0 construct theEffect done = theEffect (loop stream0) where loop :: Stream f m r %1-> m b loop stream = stream & \case Return r -> Control.return $ done r Effect m -> m Control.>>= loop Step f -> Control.return $ construct $ Control.fmap (theEffect . loop) f {-# INLINABLE destroy #-}