content: {-# LANGUAGE LambdaCase #-}
  {-# LANGUAGE LinearTypes #-}
  {-# LANGUAGE QualifiedDo #-}
  {-# LANGUAGE RecordWildCards #-}
  {-# LANGUAGE ScopedTypeVariables #-}
  {-# LANGUAGE NoImplicitPrelude #-}
  {-# OPTIONS_GHC -Wno-name-shadowing #-}
  {-# OPTIONS_HADDOCK hide #-}
  
  -- | This module provides all functions that take input streams
  -- but do not return output streams.
  module Streaming.Linear.Internal.Consume
    ( -- * Consuming 'Stream's of elements
  
      -- ** IO Consumers
      stdoutLn,
      stdoutLn',
      print,
      toHandle,
      writeFile,
  
      -- ** Basic Pure Consumers
      effects,
      erase,
      drained,
      mapM_,
  
      -- ** Folds
      fold,
      fold_,
      foldM,
      foldM_,
      all,
      all_,
      any,
      any_,
      sum,
      sum_,
      product,
      product_,
      head,
      head_,
      last,
      last_,
      elem,
      elem_,
      notElem,
      notElem_,
      length,
      length_,
      toList,
      toList_,
      mconcat,
      mconcat_,
      minimum,
      minimum_,
      maximum,
      maximum_,
      foldrM,
      foldrT,
    )
  where
  
  import qualified Control.Functor.Linear as Control
  import qualified Data.Bool.Linear as Linear
  import Data.Functor.Identity
  import Data.Text (Text)
  import qualified Data.Text as Text
  import qualified Data.Text.IO as Text
  import Data.Unrestricted.Linear
  import Prelude.Linear (($), (.))
  import Streaming.Linear.Internal.Process
  import Streaming.Linear.Internal.Type
  import qualified System.IO as System
  import System.IO.Linear
  import System.IO.Resource.Linear
  import Prelude
    ( Bool (..),
      Eq (..),
      FilePath,
      Int,
      Maybe (..),
      Num (..),
      Ord (..),
      Show (..),
      id,
      (&&),
      (||),
    )
  import qualified Prelude as Prelude
  
  -- #  IO Consumers
  -------------------------------------------------------------------------------
  
  -- Note: crashes on a broken output pipe
  --
  
  -- | Write 'String's to 'System.stdout' using 'Text.putStrLn'; terminates on a broken output pipe
  --    (The name and implementation are modelled on the @Pipes.Prelude@ @stdoutLn@).
  --
  -- \>\>\> withLinearIO $ Control.fmap move $ S.stdoutLn $ S.each $ words "one two three"
  -- one
  -- two
  -- three
  stdoutLn :: Stream (Of Text) IO () %1 -> IO ()
  stdoutLn stream = stdoutLn' stream
  {-# INLINE stdoutLn #-}
  
  -- | Like stdoutLn but with an arbitrary return value
  stdoutLn' :: forall r. Stream (Of Text) IO r %1 -> IO r
  stdoutLn' stream = loop stream
    where
      loop :: Stream (Of Text) IO r %1 -> IO r
      loop stream =
        case stream of
          Return r -> Control.return r
          Effect ms -> ms Control.>>= stdoutLn'
          Step (str :> stream) -> Control.do
            fromSystemIO $ Text.putStrLn str
            stdoutLn' stream
  {-# INLINEABLE stdoutLn' #-}
  
  -- | Print the elements of a stream as they arise.
  print :: (Show a) => Stream (Of a) IO r %1 -> IO r
  print = stdoutLn' . map (Text.pack Prelude.. Prelude.show)
  
  -- | Write a stream to a handle and return the handle.
  toHandle :: Handle %1 -> Stream (Of Text) RIO r %1 -> RIO (r, Handle)
  toHandle handle stream = loop handle stream
    where
      loop :: Handle %1 -> Stream (Of Text) RIO r %1 -> RIO (r, Handle)
      loop handle stream =
        case stream of
          Return r -> Control.return (r, handle)
          Effect ms -> ms Control.>>= toHandle handle
          Step (text :> stream') -> Control.do
            handle' <- hPutStrLn handle text
            toHandle handle' stream'
  {-# INLINEABLE toHandle #-}
  
  -- | Write a stream of text as lines as lines to a file
  writeFile :: FilePath -> Stream (Of Text) RIO r %1 -> RIO r
  writeFile filepath stream = Control.do
    handle <- openFile filepath System.WriteMode
    (r, handle') <- toHandle handle stream
    hClose handle'
    Control.return r
  
  -- #  Basic Pure Consumers
  -------------------------------------------------------------------------------
  
  -- | Reduce a stream, performing its actions but ignoring its elements.
  --
  -- @
  -- \>\>\> rest <- S.effects $ S.splitAt 2 $ each' [1..5]
  -- \>\>\> S.print rest
  -- 3
  -- 4
  -- 5
  -- @
  --
  --    'effects' should be understood together with 'copy' and is subject to the rules
  --
  -- > S.effects . S.copy       = id
  -- > hoist S.effects . S.copy = id
  --
  --    The similar @effects@ and @copy@ operations in @Data.ByteString.Streaming@ obey the same rules.
  effects :: forall a m r. (Control.Monad m) => Stream (Of a) m r %1 -> m r
  effects stream = loop stream
    where
      loop :: Stream (Of a) m r %1 -> m r
      loop stream =
        case stream of
          Return r -> Control.return r
          Effect ms -> ms Control.>>= effects
          Step (_ :> stream') -> effects stream'
  {-# INLINEABLE effects #-}
  
  -- | Remove the elements from a stream of values, retaining the structure of layers.
  erase :: forall a m r. (Control.Monad m) => Stream (Of a) m r %1 -> Stream Identity m r
  erase stream = loop stream
    where
      loop :: Stream (Of a) m r %1 -> Stream Identity m r
      loop stream =
        case stream of
          Return r -> Return r
          Step (_ :> stream') -> Step $ Identity (erase stream')
          Effect ms -> Effect $ ms Control.>>= (Control.return . erase)
  {-# INLINEABLE erase #-}
  
  -- | Where a transformer returns a stream, run the effects of the stream, keeping
  --   the return value. This is usually used at the type
  --
  -- > drained :: Control.Monad m => Stream (Of a) m (Stream (Of b) m r) -> Stream (Of a) m r
  -- > drained = Control.join . Control.fmap (Control.lift . effects)
  --
  --   Here, for example, we split a stream in two places and throw out the middle segment:
  --
  -- @
  -- \>\>\> rest <- S.print $ S.drained $ S.splitAt 2 $ S.splitAt 5 $ each' [1..7]
  -- 1
  -- 2
  -- \>\>\> S.print rest
  -- 6
  -- 7
  -- @
  drained ::
    ( Control.Monad m,
      Control.Monad (t m),
      Control.Functor (t m),
      Control.MonadTrans t
    ) =>
    t m (Stream (Of a) m r) %1 ->
    t m r
  drained = Control.join . Control.fmap (Control.lift . effects)
  {-# INLINE drained #-}
  
  -- | Reduce a stream to its return value with a monadic action.
  --
  -- @
  -- \>\>\> S.mapM_ Prelude.print $ each' [1..3]
  -- 1
  -- 2
  -- 3
  -- @
  --
  -- @
  -- \>\>\> rest <- S.mapM_ Prelude.print $ S.splitAt 3 $ each' [1..10]
  -- 1
  -- 2
  -- 3
  -- \>\>\> S.sum rest
  -- 49 :> ()
  -- @
  mapM_ ::
    forall a m b r.
    (Consumable b, Control.Monad m) =>
    (a -> m b) ->
    Stream (Of a) m r %1 ->
    m r
  mapM_ f stream = loop stream
    where
      loop :: Stream (Of a) m r %1 -> m r
      loop stream =
        case stream of
          Return r -> Control.return r
          Effect ms -> ms Control.>>= mapM_ f
          Step (a :> stream') -> Control.do
            b <- f a
            Control.return $ consume b
            mapM_ f stream'
  {-# INLINEABLE mapM_ #-}
  
  -- #  Folds
  -------------------------------------------------------------------------------
  
  -- | Strict fold of a 'Stream' of elements that preserves the return value.
  --   This does not short circuit and all effects are performed.
  --   The third parameter will often be 'id' where a fold is written by hand:
  --
  -- @
  -- \>\>\> S.fold (+) 0 id $ each' [1..10]
  -- 55 :> ()
  -- @
  --
  -- @
  -- \>\>\> S.fold (*) 1 id $ S.fold (+) 0 id $ S.copy $ each' [1..10]
  -- 3628800 :> (55 :> ())
  -- @
  --
  --    It can be used to replace a standard Haskell type with one more suited to
  --    writing a strict accumulation function. It is also crucial to the
  --    Applicative instance for @Control.Foldl.Fold@  We can apply such a fold
  --    @purely@
  --
  -- > Control.Foldl.purely S.fold :: Control.Monad m => Fold a b -> Stream (Of a) m r %1-> m (Of b r)
  --
  --    Thus, specializing a bit:
  --
  -- > L.purely S.fold L.sum :: Stream (Of Int) Int r %1-> m (Of Int r)
  -- > mapped (L.purely S.fold L.sum) :: Stream (Stream (Of Int)) IO r %1-> Stream (Of Int) IO r
  --
  --    Here we use the Applicative instance for @Control.Foldl.Fold@ to
  --    stream three-item segments of a stream together with their sums and products.
  --
  -- @
  -- \>\>\> S.print $ mapped (L.purely S.fold (liftA3 (,,) L.list L.product L.sum)) $ chunksOf 3 $ each' [1..10]
  -- ([1,2,3],6,6)
  -- ([4,5,6],120,15)
  -- ([7,8,9],504,24)
  -- ([10],10,10)
  -- @
  fold ::
    forall x a b m r.
    (Control.Monad m) =>
    (x -> a -> x) ->
    x ->
    (x -> b) ->
    Stream (Of a) m r %1 ->
    m (Of b r)
  fold f x g stream = loop stream
    where
      loop :: Stream (Of a) m r %1 -> m (Of b r)
      loop stream =
        case stream of
          Return r -> Control.return $ g x :> r
          Effect ms -> ms Control.>>= fold f x g
          Step (a :> stream') -> fold f (f x a) g stream'
  {-# INLINEABLE fold #-}
  
  -- | Strict fold of a 'Stream' of elements, preserving only the result of the fold, not
  --    the return value of the stream. This does not short circuit and all effects
  --    are performed. The third parameter will often be 'id' where a fold
  --    is written by hand:
  --
  -- @
  -- \>\>\> S.fold_ (+) 0 id $ each [1..10]
  -- 55
  -- @
  --
  --    It can be used to replace a standard Haskell type with one more suited to
  --    writing a strict accumulation function. It is also crucial to the
  --    Applicative instance for @Control.Foldl.Fold@
  --
  -- > Control.Foldl.purely fold :: Control.Monad m => Fold a b -> Stream (Of a) m () %1-> m b
  fold_ ::
    forall x a b m r.
    (Control.Monad m, Consumable r) =>
    (x -> a -> x) ->
    x ->
    (x -> b) ->
    Stream (Of a) m r %1 ->
    m b
  fold_ f x g stream = loop stream
    where
      loop :: Stream (Of a) m r %1 -> m b
      loop stream =
        case stream of
          Return r -> lseq r $ Control.return $ g x
          Effect ms -> ms Control.>>= fold_ f x g
          Step (a :> stream') -> fold_ f (f x a) g stream'
  {-# INLINEABLE fold_ #-}
  
  -- Note: We can't use 'Of' since the left component is unrestricted.
  -- Remark: to use the (`m x`) in the folding function that is the first
  -- argument, we must bind to it. Since `m` is a `Control.Monad`, we need
  -- the folding function to consume `x` linearly.
  --
  
  -- | Strict, monadic fold of the elements of a @Stream (Of a)@
  --
  -- > Control.Foldl.impurely foldM :: Control.Monad m => FoldM a b -> Stream (Of a) m r %1-> m (b, r)
  --
  --   Thus to accumulate the elements of a stream as a vector, together with a random
  --   element we might write:
  --
  -- @
  -- \>\>\> L.impurely S.foldM (liftA2 (,) L.vectorM L.random) $ each' [1..10::Int] :: IO (Of (Vector Int, Maybe Int) ())
  -- ([1,2,3,4,5,6,7,8,9,10],Just 9) :> ()
  -- @
  foldM ::
    forall x a m b r.
    (Control.Monad m) =>
    (x %1 -> a -> m x) ->
    m x ->
    (x %1 -> m b) ->
    Stream (Of a) m r %1 ->
    m (b, r)
  foldM f mx g stream = loop stream
    where
      loop :: Stream (Of a) m r %1 -> m (b, r)
      loop stream =
        case stream of
          Return r -> mx Control.>>= g Control.>>= (\b -> Control.return (b, r))
          Effect ms -> ms Control.>>= foldM f mx g
          Step (a :> stream') -> foldM f (mx Control.>>= \x -> f x a) g stream'
  {-# INLINEABLE foldM #-}
  
  -- | Strict, monadic fold of the elements of a @Stream (Of a)@
  --
  -- > Control.Foldl.impurely foldM_ :: Control.Monad m => FoldM a b -> Stream (Of a) m () %1-> m b
  foldM_ ::
    forall a m x b r.
    (Control.Monad m, Consumable r) =>
    (x %1 -> a -> m x) ->
    m x ->
    (x %1 -> m b) ->
    Stream (Of a) m r %1 ->
    m b
  foldM_ f mx g stream = loop stream
    where
      loop :: Stream (Of a) m r %1 -> m b
      loop stream =
        case stream of
          Return r -> lseq r $ mx Control.>>= g
          Effect ms -> ms Control.>>= foldM_ f mx g
          Step (a :> stream') -> foldM_ f (mx Control.>>= \x -> f x a) g stream'
  {-# INLINEABLE foldM_ #-}
  
  -- | Note: does not short circuit
  all :: (Control.Monad m) => (a -> Bool) -> Stream (Of a) m r %1 -> m (Of Bool r)
  all f stream = fold (&&) True id (map f stream)
  {-# INLINEABLE all #-}
  
  -- | Note: does not short circuit
  all_ :: (Consumable r, Control.Monad m) => (a -> Bool) -> Stream (Of a) m r %1 -> m Bool
  all_ f stream = fold_ (&&) True id (map f stream)
  {-# INLINEABLE all_ #-}
  
  -- | Note: does not short circuit
  any :: (Control.Monad m) => (a -> Bool) -> Stream (Of a) m r %1 -> m (Of Bool r)
  any f stream = fold (||) False id (map f stream)
  {-# INLINEABLE any #-}
  
  -- | Note: does not short circuit
  any_ :: (Consumable r, Control.Monad m) => (a -> Bool) -> Stream (Of a) m r %1 -> m Bool
  any_ f stream = fold_ (||) False id (map f stream)
  {-# INLINEABLE any_ #-}
  
  -- | Fold a 'Stream' of numbers into their sum with the return value
  --
  -- >  mapped S.sum :: Stream (Stream (Of Int)) m r %1-> Stream (Of Int) m r
  --
  -- @
  -- \>\>\> S.sum $ each' [1..10]
  -- 55 :> ()
  -- @
  --
  -- @
  -- \>\>\> (n :> rest)  <- S.sum $ S.splitAt 3 $ each' [1..10]
  -- \>\>\> System.IO.print n
  -- 6
  -- \>\>\> (m :> rest') <- S.sum $ S.splitAt 3 rest
  -- \>\>\> System.IO.print m
  -- 15
  -- \>\>\> S.print rest'
  -- 7
  -- 8
  -- 9
  -- 10
  -- @
  sum :: (Control.Monad m, Num a) => Stream (Of a) m r %1 -> m (Of a r)
  sum stream = fold (+) 0 id stream
  {-# INLINE sum #-}
  
  -- | Fold a 'Stream' of numbers into their sum
  sum_ :: (Control.Monad m, Num a) => Stream (Of a) m () %1 -> m a
  sum_ stream = fold_ (+) 0 id stream
  {-# INLINE sum_ #-}
  
  -- | Fold a 'Stream' of numbers into their product with the return value
  --
  -- >  mapped product :: Stream (Stream (Of Int)) m r -> Stream (Of Int) m r
  product :: (Control.Monad m, Num a) => Stream (Of a) m r %1 -> m (Of a r)
  product stream = fold (*) 1 id stream
  {-# INLINE product #-}
  
  -- | Fold a 'Stream' of numbers into their product
  product_ :: (Control.Monad m, Num a) => Stream (Of a) m () %1 -> m a
  product_ stream = fold_ (*) 1 id stream
  {-# INLINE product_ #-}
  
  -- | Note that 'head' exhausts the rest of the stream following the
  -- first element, performing all monadic effects via 'effects'
  head :: (Control.Monad m) => Stream (Of a) m r %1 -> m (Of (Maybe a) r)
  head str =
    case str of
      Return r -> Control.return (Nothing :> r)
      Effect m -> m Control.>>= head
      Step (a :> rest) ->
        effects rest Control.>>= \r -> Control.return (Just a :> r)
  {-# INLINEABLE head #-}
  
  -- | Note that 'head' exhausts the rest of the stream following the
  -- first element, performing all monadic effects via 'effects'
  head_ :: (Consumable r, Control.Monad m) => Stream (Of a) m r %1 -> m (Maybe a)
  head_ str =
    case str of
      Return r -> lseq r $ Control.return Nothing
      Effect m -> m Control.>>= head_
      Step (a :> rest) ->
        effects rest Control.>>= \r -> lseq r $ Control.return (Just a)
  {-# INLINEABLE head_ #-}
  
  last :: (Control.Monad m) => Stream (Of a) m r %1 -> m (Of (Maybe a) r)
  last = loop Nothing
    where
      loop ::
        (Control.Monad m) =>
        Maybe a ->
        Stream (Of a) m r %1 ->
        m (Of (Maybe a) r)
      loop m s =
        case s of
          Return r -> Control.return (m :> r)
          Effect m -> m Control.>>= last
          Step (a :> rest) -> loop (Just a) rest
  {-# INLINEABLE last #-}
  
  last_ :: (Consumable r, Control.Monad m) => Stream (Of a) m r %1 -> m (Maybe a)
  last_ = loop Nothing
    where
      loop ::
        (Consumable r, Control.Monad m) =>
        Maybe a ->
        Stream (Of a) m r %1 ->
        m (Maybe a)
      loop m s =
        case s of
          Return r -> lseq r $ Control.return m
          Effect m -> m Control.>>= last_
          Step (a :> rest) -> loop (Just a) rest
  {-# INLINEABLE last_ #-}
  
  elem ::
    forall a m r.
    (Control.Monad m, Eq a) =>
    a ->
    Stream (Of a) m r %1 ->
    m (Of Bool r)
  elem a stream = loop stream
    where
      loop :: Stream (Of a) m r %1 -> m (Of Bool r)
      loop stream =
        case stream of
          Return r -> Control.return $ False :> r
          Effect ms -> ms Control.>>= elem a
          Step (a' :> stream') -> case a == a' of
            True -> effects stream' Control.>>= (\r -> Control.return $ True :> r)
            False -> elem a stream'
  {-# INLINEABLE elem #-}
  
  infix 4 `elem` -- same fixity as base.elem
  
  elem_ ::
    forall a m r.
    (Consumable r, Control.Monad m, Eq a) =>
    a ->
    Stream (Of a) m r %1 ->
    m Bool
  elem_ a stream = loop stream
    where
      loop :: Stream (Of a) m r %1 -> m Bool
      loop stream =
        case stream of
          Return r -> lseq r $ Control.return False
          Effect ms -> ms Control.>>= elem_ a
          Step (a' :> stream') -> case a == a' of
            True -> effects stream' Control.>>= \r -> lseq r $ Control.return True
            False -> elem_ a stream'
  {-# INLINEABLE elem_ #-}
  
  -- | Exhaust a stream deciding whether @a@ was an element.
  notElem :: (Control.Monad m, Eq a) => a -> Stream (Of a) m r %1 -> m (Of Bool r)
  notElem a stream = Control.fmap negate $ elem a stream
    where
      negate :: Of Bool r %1 -> Of Bool r
      negate (b :> r) = Prelude.not b :> r
  {-# INLINE notElem #-}
  
  notElem_ :: (Consumable r, Control.Monad m, Eq a) => a -> Stream (Of a) m r %1 -> m Bool
  notElem_ a stream = Control.fmap Linear.not $ elem_ a stream
  {-# INLINE notElem_ #-}
  
  -- | Run a stream, keeping its length and its return value.
  --
  -- @
  -- \>\>\> S.print $ mapped S.length $ chunksOf 3 $ S.each' [1..10]
  -- 3
  -- 3
  -- 3
  -- 1
  -- @
  length :: (Control.Monad m) => Stream (Of a) m r %1 -> m (Of Int r)
  length = fold (\n _ -> n + 1) 0 id
  {-# INLINE length #-}
  
  -- | Run a stream, remembering only its length:
  --
  -- @
  -- \>\>\> runIdentity $ S.length_ (S.each [1..10] :: Stream (Of Int) Identity ())
  -- 10
  -- @
  length_ :: (Consumable r, Control.Monad m) => Stream (Of a) m r %1 -> m Int
  length_ = fold_ (\n _ -> n + 1) 0 id
  {-# INLINE length_ #-}
  
  -- | Convert an effectful 'Stream' into a list alongside the return value
  --
  -- >  mapped toList :: Stream (Stream (Of a) m) m r %1-> Stream (Of [a]) m r
  --
  --    Like 'toList_', 'toList' breaks streaming; unlike 'toList_' it /preserves the return value/
  --    and thus is frequently useful with e.g. 'mapped'
  --
  -- @
  -- \>\>\> S.print $ mapped S.toList $ chunksOf 3 $ each' [1..9]
  -- [1,2,3]
  -- [4,5,6]
  -- [7,8,9]
  -- @
  --
  -- @
  -- \>\>\> S.print $ mapped S.toList $ chunksOf 2 $ S.replicateM 4 getLine
  -- s<Enter>
  -- t<Enter>
  -- ["s","t"]
  -- u<Enter>
  -- v<Enter>
  -- ["u","v"]
  -- @
  toList :: (Control.Monad m) => Stream (Of a) m r %1 -> m (Of [a] r)
  toList = fold (\diff a ls -> diff (a : ls)) id (\diff -> diff [])
  {-# INLINE toList #-}
  
  -- | Convert an effectful @Stream (Of a)@ into a list of @as@
  --
  --    Note: Needless to say, this function does not stream properly.
  --    It is basically the same as Prelude 'mapM' which, like 'replicateM',
  --    'sequence' and similar operations on traversable containers
  --    is a leading cause of space leaks.
  toList_ :: (Control.Monad m) => Stream (Of a) m () %1 -> m [a]
  toList_ = fold_ (\diff a ls -> diff (a : ls)) id (\diff -> diff [])
  {-# INLINE toList_ #-}
  
  -- | Fold streamed items into their monoidal sum
  mconcat :: (Control.Monad m, Prelude.Monoid w) => Stream (Of w) m r %1 -> m (Of w r)
  mconcat = fold (Prelude.<>) Prelude.mempty id
  {-# INLINE mconcat #-}
  
  mconcat_ ::
    (Consumable r, Control.Monad m, Prelude.Monoid w) =>
    Stream (Of w) m r %1 ->
    m w
  mconcat_ = fold_ (Prelude.<>) Prelude.mempty id
  {-# INLINE mconcat_ #-}
  
  minimum :: (Control.Monad m, Ord a) => Stream (Of a) m r %1 -> m (Of (Maybe a) r)
  minimum = fold getMin Nothing id . map Just
  {-# INLINE minimum #-}
  
  minimum_ ::
    (Consumable r, Control.Monad m, Ord a) =>
    Stream (Of a) m r %1 ->
    m (Maybe a)
  minimum_ = fold_ getMin Nothing id . map Just
  {-# INLINE minimum_ #-}
  
  maximum :: (Control.Monad m, Ord a) => Stream (Of a) m r %1 -> m (Of (Maybe a) r)
  maximum = fold getMax Nothing id . map Just
  {-# INLINE maximum #-}
  
  maximum_ ::
    (Consumable r, Control.Monad m, Ord a) =>
    Stream (Of a) m r %1 ->
    m (Maybe a)
  maximum_ = fold_ getMax Nothing id . map Just
  {-# INLINE maximum_ #-}
  
  getMin :: (Ord a) => Maybe a -> Maybe a -> Maybe a
  getMin = mCompare Prelude.min
  
  getMax :: (Ord a) => Maybe a -> Maybe a -> Maybe a
  getMax = mCompare Prelude.max
  
  mCompare :: (Ord a) => (a -> a -> a) -> Maybe a -> Maybe a -> Maybe a
  mCompare _ Nothing Nothing = Nothing
  mCompare _ (Just a) Nothing = Just a
  mCompare _ Nothing (Just a) = Just a
  mCompare comp (Just x) (Just y) = Just $ comp x y
  
  -- | A natural right fold for consuming a stream of elements.
  --    See also the more general 'iterT' in the 'Streaming' module and the
  --    still more general 'destroy'
  foldrM ::
    forall a m r.
    (Control.Monad m) =>
    (a -> m r %1 -> m r) ->
    Stream (Of a) m r %1 ->
    m r
  foldrM step stream = loop stream
    where
      loop :: Stream (Of a) m r %1 -> m r
      loop stream =
        case stream of
          Return r -> Control.return r
          Effect m -> m Control.>>= foldrM step
          Step (a :> as) -> step a (foldrM step as)
  {-# INLINEABLE foldrM #-}
  
  -- | A natural right fold for consuming a stream of elements.
  --    See also the more general 'iterTM' in the 'Streaming' module
  --    and the still more general 'destroy'
  --
  -- > foldrT (\a p -> Streaming.yield a >> p) = id
  foldrT ::
    forall a t m r.
    (Control.Monad m, Control.MonadTrans t, Control.Monad (t m)) =>
    (a -> t m r %1 -> t m r) ->
    Stream (Of a) m r %1 ->
    t m r
  foldrT step stream = loop stream
    where
      loop :: Stream (Of a) m r %1 -> t m r
      loop stream =
        case stream of
          Return r -> Control.return r
          Effect ms -> (Control.lift ms) Control.>>= foldrT step
          Step (a :> as) -> step a (foldrT step as)
  {-# INLINEABLE foldrT #-}
  