3-- Module : Streamly.Internal.Data.StreamK
4-- Copyright : (c) 2017 Composewell Technologies
7-- Maintainer : streamly@composewell.com
8-- Stability : experimental
11module Streamly.Internal.Data.StreamK
14 -- | To execute the code examples provided in this module in ghci, please
15 -- run the following commands first.
19 module Streamly.Internal.Data.StreamK.Type
21 , module Streamly.Internal.Data.StreamK.Transformer
27 -- * Specialized Generation
49 , parseBreakChunksGeneric
52 -- ** Specialized Folds
77 -- ** By folding (scans)
115 -- ** Transformation comprehensions
118 -- ** Transforming Inner Monad
124 -- * Resource Management
129#include "ArrayMacros.h"
133import Control.Exception (mask_, Exception)
134import Control.Monad (void, join)
135import Control.Monad.Catch (MonadCatch)
136import Control.Monad.IO.Class (MonadIO(..))
137import Data.Ord (comparing)
138import Data.Proxy (Proxy(..))
139import GHC.Types (SPEC(..))
140import Streamly.Internal.Data.Array.Type (Array(..))
141import Streamly.Internal.Data.Fold.Type (Fold(..))
142import Streamly.Internal.Data.IOFinalizer (newIOFinalizer, runIOFinalizer)
143import Streamly.Internal.Data.ParserK.Type (ParserK)
144import Streamly.Internal.Data.Producer.Type (Producer(..))
145import Streamly.Internal.Data.SVar.Type (adaptState, defState)
146import Streamly.Internal.Data.Unbox (sizeOf, Unbox)
148import qualified Control.Monad.Catch as MC
149import qualified Streamly.Internal.Data.Array.Type as Array
150import qualified Streamly.Internal.Data.Array.Generic as GenArr
151import qualified Streamly.Internal.Data.Fold.Type as FL
152import qualified Streamly.Internal.Data.Parser as Parser
153import qualified Streamly.Internal.Data.Parser.Type as PR
154import qualified Streamly.Internal.Data.ParserK.Type as ParserK
155import qualified Streamly.Internal.Data.Stream as Stream
156import qualified Prelude
159 hiding (Foldable(..), last, map, mapM, mapM_, repeat, sequence,
160 take, filter, all, any, takeWhile, drop, dropWhile,
161 notElem, head, tail, init, zipWith, lookup,
162 (!!), replicate, reverse, concatMap, iterate, splitAt)
163import Data.Foldable (sum, length)
164import Streamly.Internal.Data.StreamK.Type
165import Streamly.Internal.Data.StreamK.Transformer
166import Streamly.Internal.Data.Parser (ParseError(..))
168#include "DocTestDataStreamK.hs"
170-- | Convert a fused 'Stream' to 'StreamK'.
174-- >>> s1 = StreamK.fromStream $ Stream.fromList [1,2]
175-- >>> s2 = StreamK.fromStream $ Stream.fromList [3,4]
176-- >>> Stream.fold Fold.toList $ StreamK.toStream $ s1 `StreamK.append` s2
179{-# INLINE fromStream #-}
180fromStream :: Monad m => Stream.Stream m a -> StreamK m a
181fromStream = Stream.toStreamK
183-- | Convert a 'StreamK' to a fused 'Stream'.
185{-# INLINE toStream #-}
186toStream :: Applicative m => StreamK m a -> Stream.Stream m a
187toStream = Stream.fromStreamK
189-------------------------------------------------------------------------------
191-------------------------------------------------------------------------------
194-- Generalization of concurrent streams/SVar via unfoldr.
196-- Unfold a value into monadic actions and then run the resulting monadic
197-- actions to generate a stream. Since the step of generating the monadic
198-- action and running them are decoupled we can run the monadic actions
199-- cooncurrently. For example, the seed could be a list of monadic actions or a
200-- pure stream of monadic actions.
202-- We can have different flavors of this depending on the stream type t. The
203-- concurrent version could be async or ahead etc. Depending on how we queue
204-- back the feedback portion b, it could be DFS or BFS style.
206unfoldrA :: (b -> Maybe (m a, b)) -> b -> StreamK m a
210-------------------------------------------------------------------------------
212-------------------------------------------------------------------------------
215-- >>> repeatM = StreamK.sequence . StreamK.repeat
216-- >>> repeatM = fix . StreamK.consM
217-- >>> repeatM = cycle1 . StreamK.fromEffect
219-- Generate a stream by repeatedly executing a monadic action forever.
223-- StreamK.repeatM (threadDelay 1000000 >> print 1)
225-- & StreamK.fold Fold.drain
228repeatM :: Monad m => m a -> StreamK m a
229repeatM = repeatMWith consM
231{-# INLINE replicateM #-}
232replicateM :: Monad m => Int -> m a -> StreamK m a
233replicateM = replicateMWith consM
234{-# INLINE replicate #-}
235replicate :: Int -> a -> StreamK m a
238 go cnt = if cnt <= 0 then nil else a `cons` go (cnt - 1)
240{-# INLINE fromIndicesM #-}
241fromIndicesM :: Monad m => (Int -> m a) -> StreamK m a
242fromIndicesM = fromIndicesMWith consM
243{-# INLINE fromIndices #-}
244fromIndices :: (Int -> a) -> StreamK m a
245fromIndices gen = go 0
247 go n = gen n `cons` go (n + 1)
250-- >>> iterate f x = x `StreamK.cons` iterate f x
252-- Generate an infinite stream with @x@ as the first element and each
253-- successive element derived by applying the function @f@ on the previous
256-- >>> StreamK.toList $ StreamK.take 5 $ StreamK.iterate (+1) 1
259{-# INLINE iterate #-}
260iterate :: (a -> a) -> a -> StreamK m a
263 go !s = cons s (go (step s))
266-- >>> iterateM f m = m >>= \a -> return a `StreamK.consM` iterateM f (f a)
268-- Generate an infinite stream with the first element generated by the action
269-- @m@ and each successive element derived by applying the monadic function
270-- @f@ on the previous element.
273-- StreamK.iterateM (\x -> print x >> return (x + 1)) (return 0)
281{-# INLINE iterateM #-}
282iterateM :: Monad m => (a -> m a) -> m a -> StreamK m a
283iterateM = iterateMWith consM
285-------------------------------------------------------------------------------
287-------------------------------------------------------------------------------
289{-# INLINE fromList #-}
290fromList :: [a] -> StreamK m a
291fromList = fromFoldable
293-------------------------------------------------------------------------------
294-- Elimination by Folding
295-------------------------------------------------------------------------------
298foldr1 :: Monad m => (a -> a -> a) -> StreamK m a -> m (Maybe a)
302 Nothing -> return Nothing
303 Just (h, t) -> fmap Just (go h t)
307 single a = return $ step a p
308 yieldk a r = fmap (step p) (go a r)
309 in foldStream defState yieldk single stp m1
311-- | Fold a stream using the supplied left 'Fold' and reducing the resulting
312-- expression strictly at each step. The behavior is similar to 'foldl''. A
313-- 'Fold' can terminate early without consuming the full stream. See the
314-- documentation of individual 'Fold's for termination behavior.
318-- >>> fold f = fmap fst . StreamK.foldBreak f
319-- >>> fold f = StreamK.parseD (Parser.fromFold f)
323-- >>> StreamK.fold Fold.sum $ StreamK.fromStream $ Stream.enumerateFromTo 1 100
326{-# INLINABLE fold #-}
327fold :: Monad m => FL.Fold m a b -> StreamK m a -> m b
328fold (FL.Fold step begin _ final) m = do
331 FL.Partial fs -> go fs m
332 FL.Done fb -> return fb
337 single a = step acc a
339 FL.Partial s -> final s
340 FL.Done b1 -> return b1
341 yieldk a r = step acc a
343 FL.Partial s -> go s r
344 FL.Done b1 -> return b1
345 in foldStream defState yieldk single stop m1
347-- | Fold resulting in either breaking the stream or continuation of the fold.
348-- Instead of supplying the input stream in one go we can run the fold multiple
349-- times, each time supplying the next segment of the input stream. If the fold
350-- has not yet finished it returns a fold that can be run again otherwise it
351-- returns the fold result and the residual stream.
354{-# INLINE foldEither #-}
355foldEither :: Monad m =>
356 Fold m a b -> StreamK m a -> m (Either (Fold m a b) (b, StreamK m a))
357foldEither (FL.Fold step begin done final) m = do
360 FL.Partial fs -> go fs m
361 FL.Done fb -> return $ Right (fb, m)
367 let f = Fold step (return $ FL.Partial acc) done final
373 let f = Fold step (return $ FL.Partial s) done final
375 FL.Done b1 -> return $ Right (b1, nil)
379 FL.Partial s -> go s r
380 FL.Done b1 -> return $ Right (b1, r)
381 in foldStream defState yieldk single stop m1
383-- | Like 'fold' but also returns the remaining stream. The resulting stream
384-- would be 'StreamK.nil' if the stream finished before the fold.
386{-# INLINE foldBreak #-}
387foldBreak :: Monad m => Fold m a b -> StreamK m a -> m (b, StreamK m a)
388foldBreak fld strm = do
389 r <- foldEither fld strm
391 Right res -> return res
392 Left (Fold _ initial _ final) -> do
395 FL.Done _ -> error "foldBreak: unreachable state"
400-- XXX Array folds can be implemented using this.
401-- foldContainers? Specialized to foldArrays.
403-- | Generate streams from individual elements of a stream and fold the
404-- concatenation of those streams using the supplied fold. Return the result of
405-- the fold and residual stream.
407-- For example, this can be used to efficiently fold an Array Word8 stream
411{-# INLINE foldConcat #-}
412foldConcat :: Monad m =>
413 Producer m a b -> Fold m b c -> StreamK m a -> m (c, StreamK m a)
415 (Producer pstep pinject pextract)
416 (Fold fstep begin _ final)
421 FL.Partial fs -> go fs stream
422 FL.Done fb -> return (fb, stream)
432 res <- go1 SPEC acc st
439 return (b, fromPure x)
442 res <- go1 SPEC acc st
447 return (b, x `cons` r)
448 in foldStream defState yieldk single stop m1
454 Stream.Yield x s -> do
457 FL.Done b -> return $ Right (b, s)
458 FL.Partial fs1 -> go1 SPEC fs1 s
459 Stream.Skip s -> go1 SPEC fs s
460 Stream.Stop -> return $ Left fs
462------------------------------------------------------------------------------
464------------------------------------------------------------------------------
467head :: Monad m => StreamK m a -> m (Maybe a)
468-- head = foldrM (\x _ -> return $ Just x) (return Nothing)
470 let stop = return Nothing
471 single a = return (Just a)
472 yieldk a _ = return (Just a)
473 in foldStream defState yieldk single stop m
476elem :: (Monad m, Eq a) => a -> StreamK m a -> m Bool
480 let stop = return False
481 single a = return (a == e)
482 yieldk a r = if a == e then return True else go r
483 in foldStream defState yieldk single stop m1
485{-# INLINE notElem #-}
486notElem :: (Monad m, Eq a) => a -> StreamK m a -> m Bool
490 let stop = return True
491 single a = return (a /= e)
492 yieldk a r = if a == e then return False else go r
493 in foldStream defState yieldk single stop m1
496all :: Monad m => (a -> Bool) -> StreamK m a -> m Bool
500 let single a | p a = return True
501 | otherwise = return False
502 yieldk a r | p a = go r
503 | otherwise = return False
504 in foldStream defState yieldk single (return True) m1
507any :: Monad m => (a -> Bool) -> StreamK m a -> m Bool
511 let single a | p a = return True
512 | otherwise = return False
513 yieldk a r | p a = return True
515 in foldStream defState yieldk single (return False) m1
517-- | Extract the last element of the stream, if any.
519last :: Monad m => StreamK m a -> m (Maybe a)
520last = foldlx' (\_ y -> Just y) Nothing id
522{-# INLINE minimum #-}
523minimum :: (Monad m, Ord a) => StreamK m a -> m (Maybe a)
527 let stop = return Nothing
528 single a = return (Just a)
529 yieldk a r = go (Just a) r
530 in foldStream defState yieldk single stop m1
533 let stop = return (Just res)
536 then return (Just res)
542 in foldStream defState yieldk single stop m1
544{-# INLINE minimumBy #-}
547 => (a -> a -> Ordering) -> StreamK m a -> m (Maybe a)
548minimumBy cmp = go Nothing
551 let stop = return Nothing
552 single a = return (Just a)
553 yieldk a r = go (Just a) r
554 in foldStream defState yieldk single stop m1
557 let stop = return (Just res)
558 single a = case cmp res a of
559 GT -> return (Just a)
560 _ -> return (Just res)
561 yieldk a r = case cmp res a of
564 in foldStream defState yieldk single stop m1
566{-# INLINE maximum #-}
567maximum :: (Monad m, Ord a) => StreamK m a -> m (Maybe a)
571 let stop = return Nothing
572 single a = return (Just a)
573 yieldk a r = go (Just a) r
574 in foldStream defState yieldk single stop m1
577 let stop = return (Just res)
581 else return (Just res)
586 in foldStream defState yieldk single stop m1
588{-# INLINE maximumBy #-}
589maximumBy :: Monad m => (a -> a -> Ordering) -> StreamK m a -> m (Maybe a)
590maximumBy cmp = go Nothing
593 let stop = return Nothing
594 single a = return (Just a)
595 yieldk a r = go (Just a) r
596 in foldStream defState yieldk single stop m1
599 let stop = return (Just res)
600 single a = case cmp res a of
601 GT -> return (Just res)
603 yieldk a r = case cmp res a of
604 GT -> go (Just res) r
606 in foldStream defState yieldk single stop m1
609(!!) :: Monad m => StreamK m a -> Int -> m (Maybe a)
613 let single a | n == 0 = return $ Just a
614 | otherwise = return Nothing
615 yieldk a x | n < 0 = return Nothing
616 | n == 0 = return $ Just a
617 | otherwise = go (n - 1) x
618 in foldStream defState yieldk single (return Nothing) m1
621lookup :: (Monad m, Eq a) => a -> StreamK m (a, b) -> m (Maybe b)
625 let single (a, b) | a == e = return $ Just b
626 | otherwise = return Nothing
627 yieldk (a, b) x | a == e = return $ Just b
629 in foldStream defState yieldk single (return Nothing) m1
632findM :: Monad m => (a -> m Bool) -> StreamK m a -> m (Maybe a)
638 if b then return $ Just a else return Nothing
641 if b then return $ Just a else go x
642 in foldStream defState yieldk single (return Nothing) m1
645find :: Monad m => (a -> Bool) -> StreamK m a -> m (Maybe a)
646find p = findM (return . p)
648{-# INLINE findIndices #-}
649findIndices :: (a -> Bool) -> StreamK m a -> StreamK m Int
652 go offset m1 = mkStream $ \st yld sng stp ->
653 let single a | p a = sng offset
655 yieldk a x | p a = yld offset $ go (offset + 1) x
656 | otherwise = foldStream (adaptState st) yld sng stp $
658 in foldStream (adaptState st) yieldk single stp m1
660------------------------------------------------------------------------------
662------------------------------------------------------------------------------
664-- | Apply a monadic action to each element of the stream and discard the
665-- output of the action.
667mapM_ :: Monad m => (a -> m b) -> StreamK m a -> m ()
672 single a = void (f a)
673 yieldk a r = f a >> go r
674 in foldStream defState yieldk single stop m1
677mapM :: Monad m => (a -> m b) -> StreamK m a -> StreamK m b
680------------------------------------------------------------------------------
682------------------------------------------------------------------------------
684{-# INLINABLE toList #-}
685toList :: Monad m => StreamK m a -> m [a]
688-- Based on suggestions by David Feuer and Pranay Sashank
690hoist :: (Monad m, Monad n)
691 => (forall x. m x -> n x) -> StreamK m a -> StreamK n a
693 mkStream $ \st yld sng stp ->
694 let single = return . sng
695 yieldk a s = return $ yld a (hoist f s)
697 state = adaptState st
698 in join . f $ foldStreamShared state yieldk single stop str
700-------------------------------------------------------------------------------
701-- Transformation by folding (Scans)
702-------------------------------------------------------------------------------
704{-# INLINE scanlx' #-}
705scanlx' :: (x -> a -> x) -> x -> (x -> b) -> StreamK m a -> StreamK m b
706scanlx' step begin done m =
707 cons (done begin) $ go m begin
709 go m1 !acc = mkStream $ \st yld sng stp ->
710 let single a = sng (done $ step acc a)
713 in yld (done s) (go r s)
714 in foldStream (adaptState st) yieldk single stp m1
717scanl' :: (b -> a -> b) -> b -> StreamK m a -> StreamK m b
718scanl' step begin = scanlx' step begin id
720-------------------------------------------------------------------------------
722-------------------------------------------------------------------------------
725filter :: (a -> Bool) -> StreamK m a -> StreamK m a
728 go m1 = mkStream $ \st yld sng stp ->
729 let single a | p a = sng a
731 yieldk a r | p a = yld a (go r)
732 | otherwise = foldStream st yieldk single stp r
733 in foldStream st yieldk single stp m1
736take :: Int -> StreamK m a -> StreamK m a
739 go n1 m1 = mkStream $ \st yld sng stp ->
740 let yieldk a r = yld a (go (n1 - 1) r)
743 else foldStream st yieldk sng stp m1
745{-# INLINE takeWhile #-}
746takeWhile :: (a -> Bool) -> StreamK m a -> StreamK m a
749 go m1 = mkStream $ \st yld sng stp ->
750 let single a | p a = sng a
752 yieldk a r | p a = yld a (go r)
754 in foldStream st yieldk single stp m1
757drop :: Int -> StreamK m a -> StreamK m a
758drop n m = unShare (go n m)
760 go n1 m1 = mkStream $ \st yld sng stp ->
762 yieldk _ r = foldStreamShared st yld sng stp $ go (n1 - 1) r
763 -- Somehow "<=" check performs better than a ">"
765 then foldStreamShared st yld sng stp m1
766 else foldStreamShared st yieldk single stp m1
768{-# INLINE dropWhile #-}
769dropWhile :: (a -> Bool) -> StreamK m a -> StreamK m a
772 go m1 = mkStream $ \st yld sng stp ->
773 let single a | p a = stp
775 yieldk a r | p a = foldStream st yieldk single stp r
776 | otherwise = yld a r
777 in foldStream st yieldk single stp m1
779-------------------------------------------------------------------------------
781-------------------------------------------------------------------------------
783-- Be careful when modifying this, this uses a consM (|:) deliberately to allow
784-- other stream types to overload it.
785{-# INLINE sequence #-}
786sequence :: Monad m => StreamK m (m a) -> StreamK m a
789 go m1 = mkStream $ \st yld sng stp ->
790 let single ma = ma >>= sng
791 yieldk ma r = foldStreamShared st yld sng stp $ ma `consM` go r
792 in foldStream (adaptState st) yieldk single stp m1
794-------------------------------------------------------------------------------
796-------------------------------------------------------------------------------
798{-# INLINE intersperseM #-}
799intersperseM :: Monad m => m a -> StreamK m a -> StreamK m a
800intersperseM a = prependingStart
802 prependingStart m1 = mkStream $ \st yld sng stp ->
804 foldStreamShared st yld sng stp $ return i `consM` go x
805 in foldStream st yieldk sng stp m1
806 go m2 = mkStream $ \st yld sng stp ->
807 let single i = foldStreamShared st yld sng stp $ a `consM` fromPure i
810 st yld sng stp $ a `consM` return i `consM` go x
811 in foldStream st yieldk single stp m2
813{-# INLINE intersperse #-}
814intersperse :: Monad m => a -> StreamK m a -> StreamK m a
815intersperse a = intersperseM (return a)
817{-# INLINE insertBy #-}
818insertBy :: (a -> a -> Ordering) -> a -> StreamK m a -> StreamK m a
821 go m1 = mkStream $ \st yld _ _ ->
822 let single a = case cmp x a of
823 GT -> yld a (fromPure x)
824 _ -> yld x (fromPure a)
826 yieldk a r = case cmp x a of
828 _ -> yld x (a `cons` r)
829 in foldStream st yieldk single stop m1
831------------------------------------------------------------------------------
833------------------------------------------------------------------------------
835{-# INLINE deleteBy #-}
836deleteBy :: (a -> a -> Bool) -> a -> StreamK m a -> StreamK m a
839 go m1 = mkStream $ \st yld sng stp ->
840 let single a = if eq x a then stp else sng a
841 yieldk a r = if eq x a
842 then foldStream st yld sng stp r
844 in foldStream st yieldk single stp m1
846-------------------------------------------------------------------------------
848-------------------------------------------------------------------------------
850{-# INLINE mapMaybe #-}
851mapMaybe :: (a -> Maybe b) -> StreamK m a -> StreamK m b
854 go m1 = mkStream $ \st yld sng stp ->
855 let single a = maybe stp sng (f a)
856 yieldk a r = case f a of
857 Just b -> yld b $ go r
858 Nothing -> foldStream (adaptState st) yieldk single stp r
859 in foldStream (adaptState st) yieldk single stp m1
861-------------------------------------------------------------------------------
863-------------------------------------------------------------------------------
865-- | Like Streamly.Data.Stream.'Streamly.Data.Stream.handle' but with one
866-- significant difference, this function observes exceptions from the consumer
867-- of the stream as well.
869-- You can also convert 'StreamK' to 'Stream' and use exception handling from
872-- >>> handle f s = StreamK.fromStream $ Stream.handle (\e -> StreamK.toStream (f e)) (StreamK.toStream s)
874{-# INLINABLE handle #-}
875handle :: (MonadCatch m, Exception e)
876 => (e -> m (StreamK m a)) -> StreamK m a -> StreamK m a
877handle f stream = go stream
881 go m1 = mkStream $ \st yld sng stp ->
882 let yieldk a r = yld a $ go r
884 res <- MC.try (foldStream (adaptState st) yieldk sng stp m1)
889 foldStream (adaptState st) yld sng stp r
891-------------------------------------------------------------------------------
892-- Resource Management
893-------------------------------------------------------------------------------
895-- If we are folding the stream and we do not drain the entire stream (e.g. if
896-- the fold terminates before the stream) then the finalizer will run on GC.
898-- XXX To implement a prompt cleanup, we will have to yield a cleanup function
899-- via the yield continuation. A chain of cleanup functions can be built and
900-- the entire chain can be invoked when the stream ends voluntarily or if
901-- someone decides to abandon the stream.
903-- | Like Streamly.Data.Stream.'Streamly.Data.Stream.bracketIO' but with one
904-- significant difference, this function observes exceptions from the consumer
905-- of the stream as well. Therefore, it cleans up the resource promptly when
906-- the consumer encounters an exception.
908-- You can also convert 'StreamK' to 'Stream' and use resource handling from
911-- >>> bracketIO bef aft bet = StreamK.fromStream $ Stream.bracketIO bef aft (StreamK.toStream . bet)
913{-# INLINABLE bracketIO #-}
914bracketIO :: (MonadIO m, MonadCatch m)
915 => IO b -> (b -> IO c) -> (b -> StreamK m a) -> StreamK m a
916bracketIO bef aft bet =
918 (r, ref) <- liftIO $ mask_ $ do
920 ref <- newIOFinalizer (aft r)
922 return $ go ref (bet r)
926 go ref m1 = mkStream $ \st yld sng stp ->
928 -- We can discard exceptions on continuations to make it equivalent
929 -- to StreamD, but it seems like a desirable behavior.
930 stop = liftIO (runIOFinalizer ref) >> stp
931 single a = liftIO (runIOFinalizer ref) >> sng a
932 yieldk a r = yld a $ go ref r
934 -- Do not call the finalizer twice if it has already been
935 -- called via stop continuation and stop continuation itself
936 -- generated an exception. runIOFinalizer takes care of that.
937 res <- MC.try (foldStream (adaptState st) yieldk single stop m1)
940 Left (e :: MC.SomeException) ->
941 liftIO (runIOFinalizer ref) >> MC.throwM e
943------------------------------------------------------------------------------
945------------------------------------------------------------------------------
947-- | Zipping of @n@ streams can be performed by combining the streams pair
948-- wise using 'mergeMapWith' with O(n * log n) time complexity. If used
949-- with 'concatMapWith' it will have O(n^2) performance.
950{-# INLINE zipWith #-}
951zipWith :: Monad m => (a -> b -> c) -> StreamK m a -> StreamK m b -> StreamK m c
952zipWith f = zipWithM (\a b -> return (f a b))
954{-# INLINE zipWithM #-}
955zipWithM :: Monad m =>
956 (a -> b -> m c) -> StreamK m a -> StreamK m b -> StreamK m c
961 go mx my = mkStream $ \st yld sng stp -> do
963 let single2 b = f a b >>= sng
964 yield2 b rb = f a b >>= \x -> yld x (go ra rb)
965 in foldStream (adaptState st) yield2 single2 stp my
966 let single1 a = merge a nil
968 foldStream (adaptState st) yield1 single1 stp mx
970------------------------------------------------------------------------------
972------------------------------------------------------------------------------
974{-# INLINE mergeByM #-}
975mergeByM :: Monad m =>
976 (a -> a -> m Ordering) -> StreamK m a -> StreamK m a -> StreamK m a
981 go mx my = mkStream $ \st yld sng stp -> do
982 let stop = foldStream st yld sng stp my
983 single x = foldStream st yld sng stp (goX0 x my)
984 yield x rx = foldStream st yld sng stp (goX x rx my)
985 foldStream st yield single stop mx
987 goX0 x my = mkStream $ \st yld sng _ -> do
992 GT -> yld y (fromPure x)
993 _ -> yld x (fromPure y)
997 GT -> yld y (goX0 x ry)
998 _ -> yld x (y `cons` ry)
999 in foldStream st yield single stop my
1001 goX x mx my = mkStream $ \st yld _ _ -> do
1006 GT -> yld y (x `cons` mx)
1007 _ -> yld x (goY0 mx y)
1011 GT -> yld y (goX x mx ry)
1012 _ -> yld x (goY mx y ry)
1013 in foldStream st yield single stop my
1015 goY0 mx y = mkStream $ \st yld sng _ -> do
1020 GT -> yld y (fromPure x)
1021 _ -> yld x (fromPure y)
1025 GT -> yld y (x `cons` rx)
1026 _ -> yld x (goY0 rx y)
1027 in foldStream st yield single stop mx
1029 goY mx y my = mkStream $ \st yld _ _ -> do
1034 GT -> yld y (goX0 x my)
1035 _ -> yld x (y `cons` my)
1039 GT -> yld y (goX x rx my)
1040 _ -> yld x (goY rx y my)
1041 in foldStream st yield single stop mx
1043-- | Merging of @n@ streams can be performed by combining the streams pair
1044-- wise using 'mergeMapWith' to give O(n * log n) time complexity. If used
1045-- with 'concatMapWith' it will have O(n^2) performance.
1047{-# INLINE mergeBy #-}
1048mergeBy :: (a -> a -> Ordering) -> StreamK m a -> StreamK m a -> StreamK m a
1049-- XXX GHC: This has slightly worse performance than replacing "r <- cmp x y"
1050-- with "let r = cmp x y" in the monadic version. The definition below is
1051-- exactly the same as mergeByM except this change.
1052-- mergeBy cmp = mergeByM (\a b -> return $ cmp a b)
1057 go mx my = mkStream $ \st yld sng stp -> do
1058 let stop = foldStream st yld sng stp my
1059 single x = foldStream st yld sng stp (goX0 x my)
1060 yield x rx = foldStream st yld sng stp (goX x rx my)
1061 foldStream st yield single stop mx
1063 goX0 x my = mkStream $ \st yld sng _ -> do
1067 GT -> yld y (fromPure x)
1068 _ -> yld x (fromPure y)
1071 GT -> yld y (goX0 x ry)
1072 _ -> yld x (y `cons` ry)
1073 in foldStream st yield single stop my
1075 goX x mx my = mkStream $ \st yld _ _ -> do
1079 GT -> yld y (x `cons` mx)
1080 _ -> yld x (goY0 mx y)
1083 GT -> yld y (goX x mx ry)
1084 _ -> yld x (goY mx y ry)
1085 in foldStream st yield single stop my
1087 goY0 mx y = mkStream $ \st yld sng _ -> do
1091 GT -> yld y (fromPure x)
1092 _ -> yld x (fromPure y)
1095 GT -> yld y (x `cons` rx)
1096 _ -> yld x (goY0 rx y)
1097 in foldStream st yield single stop mx
1099 goY mx y my = mkStream $ \st yld _ _ -> do
1103 GT -> yld y (goX0 x my)
1104 _ -> yld x (y `cons` my)
1107 GT -> yld y (goX x rx my)
1108 _ -> yld x (goY rx y my)
1109 in foldStream st yield single stop mx
1111------------------------------------------------------------------------------
1112-- Transformation comprehensions
1113------------------------------------------------------------------------------
1116the :: (Eq a, Monad m) => StreamK m a -> m (Maybe a)
1120 Nothing -> return Nothing
1121 Just (h, t) -> go h t
1124 let single a | h == a = return $ Just h
1125 | otherwise = return Nothing
1126 yieldk a r | h == a = go h r
1127 | otherwise = return Nothing
1128 in foldStream defState yieldk single (return $ Just h) m1
1130------------------------------------------------------------------------------
1131-- Alternative & MonadPlus
1132------------------------------------------------------------------------------
1134_alt :: StreamK m a -> StreamK m a -> StreamK m a
1135_alt m1 m2 = mkStream $ \st yld sng stp ->
1136 let stop = foldStream st yld sng stp m2
1137 in foldStream st yld sng stop m1
1139------------------------------------------------------------------------------
1141------------------------------------------------------------------------------
1144-- XXX handle and test cross thread state transfer
1147 => StreamK m a -> (e -> StreamK m a) -> StreamK m a
1149 mkStream $ \_ stp sng yld ->
1150 let run x = unStream x Nothing stp sng yieldk
1151 handle r = r `catchError` \e -> run $ h e
1152 yieldk a r = yld a (withCatchError r h)
1156-------------------------------------------------------------------------------
1158-------------------------------------------------------------------------------
1160-- Inlined definition.
1161{-# INLINE splitAt #-}
1162splitAt :: Int -> [a] -> ([a],[a])
1165 | otherwise = splitAt' n ls
1167 splitAt' :: Int -> [a] -> ([a], [a])
1168 splitAt' _ [] = ([], [])
1169 splitAt' 1 (x:xs) = ([x], xs)
1170 splitAt' m (x:xs) = (x:xs', xs'')
1172 (xs', xs'') = splitAt' (m - 1) xs
1174-- | Run a 'Parser' over a stream and return rest of the Stream.
1175{-# INLINE_NORMAL parseDBreak #-}
1180 -> m (Either ParseError b, StreamK m a)
1181parseDBreak (PR.Parser pstep initial extract) stream = do
1184 PR.IPartial s -> goStream stream [] s
1185 PR.IDone b -> return (Right b, stream)
1186 PR.IError err -> return (Left (ParseError err), stream)
1190 -- "buf" contains last few items in the stream that we may have to
1193 -- XXX currently we are using a dumb list based approach for backtracking
1194 -- buffer. This can be replaced by a sliding/ring buffer using Data.Array.
1195 -- That will allow us more efficient random back and forth movement.
1196 goStream st buf !pst =
1201 let src = Prelude.reverse buf
1202 return (Left (ParseError err), fromList src)
1204 assertM(n <= length buf)
1205 let src0 = Prelude.take n buf
1206 src = Prelude.reverse src0
1207 return (Right b, fromList src)
1208 PR.Partial _ _ -> error "Bug: parseBreak: Partial in extract"
1209 PR.Continue 0 s -> goStream nil buf s
1210 PR.Continue n s -> do
1211 assertM(n <= length buf)
1212 let (src0, buf1) = splitAt n buf
1213 src = Prelude.reverse src0
1214 goBuf nil buf1 src s
1215 single x = yieldk x nil
1219 PR.Partial 0 s -> goStream r [] s
1220 PR.Partial n s -> do
1221 assertM(n <= length (x:buf))
1222 let src0 = Prelude.take n (x:buf)
1223 src = Prelude.reverse src0
1225 PR.Continue 0 s -> goStream r (x:buf) s
1226 PR.Continue n s -> do
1227 assertM(n <= length (x:buf))
1228 let (src0, buf1) = splitAt n (x:buf)
1229 src = Prelude.reverse src0
1231 PR.Done 0 b -> return (Right b, r)
1233 assertM(n <= length (x:buf))
1234 let src0 = Prelude.take n (x:buf)
1235 src = Prelude.reverse src0
1236 return (Right b, append (fromList src) r)
1238 let src = Prelude.reverse (x:buf)
1239 return (Left (ParseError err), append (fromList src) r)
1240 in foldStream defState yieldk single stop st
1242 goBuf st buf [] !pst = goStream st buf pst
1243 goBuf st buf (x:xs) !pst = do
1246 PR.Partial 0 s -> goBuf st [] xs s
1247 PR.Partial n s -> do
1248 assert (n <= length (x:buf)) (return ())
1249 let src0 = Prelude.take n (x:buf)
1250 src = Prelude.reverse src0 ++ xs
1252 PR.Continue 0 s -> goBuf st (x:buf) xs s
1253 PR.Continue n s -> do
1254 assert (n <= length (x:buf)) (return ())
1255 let (src0, buf1) = splitAt n (x:buf)
1256 src = Prelude.reverse src0 ++ xs
1259 assert (n <= length (x:buf)) (return ())
1260 let src0 = Prelude.take n (x:buf)
1261 src = Prelude.reverse src0
1262 return (Right b, append (fromList src) st)
1264 let src = Prelude.reverse buf ++ x:xs
1265 return (Left (ParseError err), append (fromList src) st)
1267-- Using ParserD or ParserK on StreamK may not make much difference. We should
1268-- perhaps use only chunked parsing on StreamK. We can always convert a stream
1269-- to chunks before parsing. Or just have a ParserK element parser for StreamK
1270-- and convert ParserD to ParserK for element parsing using StreamK.
1271{-# INLINE parseD #-}
1273 Parser.Parser a m b -> StreamK m a -> m (Either ParseError b)
1274parseD f = fmap fst . parseDBreak f
1276-------------------------------------------------------------------------------
1278-------------------------------------------------------------------------------
1280-- The backracking buffer consists of arrays in the most-recent-first order. We
1281-- want to take a total of n array elements from this buffer. Note: when we
1282-- have to take an array partially, we must take the last part of the array.
1283{-# INLINE backTrack #-}
1284backTrack :: forall m a. Unbox a =>
1287 -> StreamK m (Array a)
1288 -> (StreamK m (Array a), [Array a])
1293 go _ [] stream = (stream, [])
1294 go n xs stream | n <= 0 = (stream, xs)
1295 go n (x:xs) stream =
1296 let len = Array.length x
1298 then go (n - len) xs (cons x stream)
1300 then (cons x stream, xs)
1301 else let !(Array contents start end) = x
1302 !start1 = end - (n * SIZE_OF(a))
1303 arr1 = Array contents start1 end
1304 arr2 = Array contents start start1
1305 in (cons arr1 stream, arr2:xs)
1307-- | A continuation to extract the result when a CPS parser is done.
1308{-# INLINE parserDone #-}
1309parserDone :: Applicative m =>
1310 ParserK.ParseResult b -> Int -> ParserK.Input a -> m (ParserK.Step a m b)
1311parserDone (ParserK.Success n b) _ _ = pure $ ParserK.Done n b
1312parserDone (ParserK.Failure n e) _ _ = pure $ ParserK.Error n e
1314-- XXX parseDBreakChunks may be faster than converting parserD to parserK and
1315-- using parseBreakChunks. We can also use parseBreak as an alternative to the
1316-- monad instance of ParserD.
1318-- | Run a 'ParserK' over a chunked 'StreamK' and return the parse result and
1319-- the remaining Stream.
1320{-# INLINE_NORMAL parseBreakChunks #-}
1322 :: (Monad m, Unbox a)
1323 => ParserK (Array a) m b
1324 -> StreamK m (Array a)
1325 -> m (Either ParseError b, StreamK m (Array a))
1326parseBreakChunks parser input = do
1327 let parserk = ParserK.runParser parser parserDone 0 0
1328 in go [] parserk input
1332 {-# INLINE goStop #-}
1333 goStop backBuf parserk = do
1334 pRes <- parserk ParserK.None
1336 -- If we stop in an alternative, it will try calling the next
1337 -- parser, the next parser may call initial returning Partial and
1338 -- then immediately we have to call extract on it.
1339 ParserK.Partial 0 cont1 ->
1341 ParserK.Partial n cont1 -> do
1343 assertM(n1 >= 0 && n1 <= sum (Prelude.map Array.length backBuf))
1344 let (s1, backBuf1) = backTrack n1 backBuf nil
1345 in go backBuf1 cont1 s1
1346 ParserK.Continue 0 cont1 ->
1347 go backBuf cont1 nil
1348 ParserK.Continue n cont1 -> do
1350 assertM(n1 >= 0 && n1 <= sum (Prelude.map Array.length backBuf))
1351 let (s1, backBuf1) = backTrack n1 backBuf nil
1352 in go backBuf1 cont1 s1
1354 return (Right b, nil)
1355 ParserK.Done n b -> do
1357 assertM(n1 >= 0 && n1 <= sum (Prelude.map Array.length backBuf))
1358 let (s1, _) = backTrack n1 backBuf nil
1359 in return (Right b, s1)
1360 ParserK.Error _ err -> do
1361 let (s1, _) = backTrack maxBound backBuf nil
1362 return (Left (ParseError err), s1)
1365 error $ "parseBreak: Partial: forward seek not implemented n = "
1366 ++ show n ++ " len = " ++ show len
1368 yieldk backBuf parserk arr stream = do
1369 pRes <- parserk (ParserK.Chunk arr)
1370 let len = Array.length arr
1372 ParserK.Partial n cont1 ->
1373 case compare n len of
1374 EQ -> go [] cont1 stream
1377 then yieldk [] cont1 arr stream
1380 bufLen = sum (Prelude.map Array.length backBuf)
1382 assertM(n1 >= 0 && n1 <= bufLen)
1383 let (s1, _) = backTrack n1 backBuf s
1386 ParserK.Continue n cont1 ->
1387 case compare n len of
1388 EQ -> go (arr:backBuf) cont1 stream
1391 then yieldk backBuf cont1 arr stream
1394 bufLen = sum (Prelude.map Array.length backBuf)
1396 assertM(n1 >= 0 && n1 <= bufLen)
1397 let (s1, backBuf1) = backTrack n1 backBuf s
1398 go backBuf1 cont1 s1
1400 ParserK.Done n b -> do
1402 assertM(n1 <= sum (Prelude.map Array.length (arr:backBuf)))
1403 let (s1, _) = backTrack n1 (arr:backBuf) stream
1404 in return (Right b, s1)
1405 ParserK.Error _ err -> do
1406 let (s1, _) = backTrack maxBound (arr:backBuf) stream
1407 return (Left (ParseError err), s1)
1409 go backBuf parserk stream = do
1410 let stop = goStop backBuf parserk
1411 single a = yieldk backBuf parserk a nil
1413 defState (yieldk backBuf parserk) single stop stream
1415{-# INLINE parseChunks #-}
1416parseChunks :: (Monad m, Unbox a) =>
1417 ParserK (Array a) m b -> StreamK m (Array a) -> m (Either ParseError b)
1418parseChunks f = fmap fst . parseBreakChunks f
1420-------------------------------------------------------------------------------
1422-------------------------------------------------------------------------------
1424{-# INLINE backTrackSingular #-}
1425backTrackSingular :: Int -> [a] -> StreamK m a -> (StreamK m a, [a])
1426backTrackSingular = go
1430 go _ [] stream = (stream, [])
1431 go n xs stream | n <= 0 = (stream, xs)
1433 let (appendBuf, newBTBuf) = splitAt n xs
1434 in (append (fromList (Prelude.reverse appendBuf)) stream, newBTBuf)
1437-- | Similar to 'parseBreak' but works on singular elements.
1439{-# INLINE_NORMAL parseBreak #-}
1441 :: forall m a b. Monad m
1442 => ParserK.ParserK a m b
1444 -> m (Either ParseError b, StreamK m a)
1445parseBreak parser input = do
1446 let parserk = ParserK.runParser parser parserDone 0 0
1447 in go [] parserk input
1451 {-# INLINE goStop #-}
1454 -> (ParserK.Input a -> m (ParserK.Step a m b))
1455 -> m (Either ParseError b, StreamK m a)
1456 goStop backBuf parserk = do
1457 pRes <- parserk ParserK.None
1459 -- If we stop in an alternative, it will try calling the next
1460 -- parser, the next parser may call initial returning Partial and
1461 -- then immediately we have to call extract on it.
1462 ParserK.Partial 0 cont1 ->
1464 ParserK.Partial n cont1 -> do
1466 assertM(n1 >= 0 && n1 <= length backBuf)
1467 let (s1, backBuf1) = backTrackSingular n1 backBuf nil
1468 in go backBuf1 cont1 s1
1469 ParserK.Continue 0 cont1 ->
1470 go backBuf cont1 nil
1471 ParserK.Continue n cont1 -> do
1473 assertM(n1 >= 0 && n1 <= length backBuf)
1474 let (s1, backBuf1) = backTrackSingular n1 backBuf nil
1475 in go backBuf1 cont1 s1
1477 return (Right b, nil)
1478 ParserK.Done n b -> do
1480 assertM(n1 >= 0 && n1 <= length backBuf)
1481 let (s1, _) = backTrackSingular n1 backBuf nil
1482 in return (Right b, s1)
1483 ParserK.Error _ err -> return (Left (ParseError err), nil)
1486 error $ "parseBreak: Partial: forward seek not implemented n = "
1491 -> (ParserK.Input a -> m (ParserK.Step a m b))
1494 -> m (Either ParseError b, StreamK m a)
1495 yieldk backBuf parserk arr stream = do
1496 pRes <- parserk (ParserK.Chunk arr)
1498 ParserK.Partial 1 cont1 -> go [] cont1 stream
1499 ParserK.Partial 0 cont1 -> go [] cont1 (cons arr stream)
1500 ParserK.Partial n _ | n > 1 -> seekErr n
1501 ParserK.Partial n cont1 -> do
1503 bufLen = length backBuf
1505 assertM(n1 >= 0 && n1 <= bufLen)
1506 let (s1, _) = backTrackSingular n1 backBuf s
1508 ParserK.Continue 1 cont1 -> go (arr:backBuf) cont1 stream
1509 ParserK.Continue 0 cont1 ->
1510 go backBuf cont1 (cons arr stream)
1511 ParserK.Continue n _ | n > 1 -> seekErr n
1512 ParserK.Continue n cont1 -> do
1514 bufLen = length backBuf
1516 assertM(n1 >= 0 && n1 <= bufLen)
1517 let (s1, backBuf1) = backTrackSingular n1 backBuf s
1518 go backBuf1 cont1 s1
1519 ParserK.Done 1 b -> pure (Right b, stream)
1520 ParserK.Done 0 b -> pure (Right b, cons arr stream)
1521 ParserK.Done n _ | n > 1 -> seekErr n
1522 ParserK.Done n b -> do
1524 bufLen = length backBuf
1526 assertM(n1 >= 0 && n1 <= bufLen)
1527 let (s1, _) = backTrackSingular n1 backBuf s
1529 ParserK.Error _ err -> return (Left (ParseError err), nil)
1533 -> (ParserK.Input a -> m (ParserK.Step a m b))
1535 -> m (Either ParseError b, StreamK m a)
1536 go backBuf parserk stream = do
1537 let stop = goStop backBuf parserk
1538 single a = yieldk backBuf parserk a nil
1540 defState (yieldk backBuf parserk) single stop stream
1542-- | Run a 'ParserK' over a 'StreamK'. Please use 'parseChunks' where possible,
1543-- for better performance.
1546 ParserK.ParserK a m b -> StreamK m a -> m (Either ParseError b)
1547parse f = fmap fst . parseBreak f
1549-------------------------------------------------------------------------------
1550-- ParserK Chunked Generic
1551-------------------------------------------------------------------------------
1553{-# INLINE backTrackGenericChunks #-}
1554backTrackGenericChunks ::
1557 -> StreamK m (GenArr.Array a)
1558 -> (StreamK m (GenArr.Array a), [GenArr.Array a])
1559backTrackGenericChunks = go
1563 go _ [] stream = (stream, [])
1564 go n xs stream | n <= 0 = (stream, xs)
1565 go n (x:xs) stream =
1566 let len = GenArr.length x
1568 then go (n - len) xs (cons x stream)
1570 then (cons x stream, xs)
1571 else let arr1 = GenArr.getSliceUnsafe (len - n) n x
1572 arr2 = GenArr.getSliceUnsafe 0 (len - n) x
1573 in (cons arr1 stream, arr2:xs)
1575-- | Similar to 'parseBreak' but works on generic arrays
1577{-# INLINE_NORMAL parseBreakChunksGeneric #-}
1578parseBreakChunksGeneric
1579 :: forall m a b. Monad m
1580 => ParserK.ParserK (GenArr.Array a) m b
1581 -> StreamK m (GenArr.Array a)
1582 -> m (Either ParseError b, StreamK m (GenArr.Array a))
1583parseBreakChunksGeneric parser input = do
1584 let parserk = ParserK.runParser parser parserDone 0 0
1585 in go [] parserk input
1589 {-# INLINE goStop #-}
1592 -> (ParserK.Input (GenArr.Array a)
1593 -> m (ParserK.Step (GenArr.Array a) m b))
1594 -> m (Either ParseError b, StreamK m (GenArr.Array a))
1595 goStop backBuf parserk = do
1596 pRes <- parserk ParserK.None
1598 -- If we stop in an alternative, it will try calling the next
1599 -- parser, the next parser may call initial returning Partial and
1600 -- then immediately we have to call extract on it.
1601 ParserK.Partial 0 cont1 ->
1603 ParserK.Partial n cont1 -> do
1605 assertM(n1 >= 0 && n1 <= sum (Prelude.map GenArr.length backBuf))
1606 let (s1, backBuf1) = backTrackGenericChunks n1 backBuf nil
1607 in go backBuf1 cont1 s1
1608 ParserK.Continue 0 cont1 ->
1609 go backBuf cont1 nil
1610 ParserK.Continue n cont1 -> do
1612 assertM(n1 >= 0 && n1 <= sum (Prelude.map GenArr.length backBuf))
1613 let (s1, backBuf1) = backTrackGenericChunks n1 backBuf nil
1614 in go backBuf1 cont1 s1
1616 return (Right b, nil)
1617 ParserK.Done n b -> do
1619 assertM(n1 >= 0 && n1 <= sum (Prelude.map GenArr.length backBuf))
1620 let (s1, _) = backTrackGenericChunks n1 backBuf nil
1621 in return (Right b, s1)
1622 ParserK.Error _ err -> return (Left (ParseError err), nil)
1625 error $ "parseBreak: Partial: forward seek not implemented n = "
1626 ++ show n ++ " len = " ++ show len
1630 -> (ParserK.Input (GenArr.Array a)
1631 -> m (ParserK.Step (GenArr.Array a) m b))
1633 -> StreamK m (GenArr.Array a)
1634 -> m (Either ParseError b, StreamK m (GenArr.Array a))
1635 yieldk backBuf parserk arr stream = do
1636 pRes <- parserk (ParserK.Chunk arr)
1637 let len = GenArr.length arr
1639 ParserK.Partial n cont1 ->
1640 case compare n len of
1641 EQ -> go [] cont1 stream
1644 then yieldk [] cont1 arr stream
1647 bufLen = sum (Prelude.map GenArr.length backBuf)
1649 assertM(n1 >= 0 && n1 <= bufLen)
1650 let (s1, _) = backTrackGenericChunks n1 backBuf s
1653 ParserK.Continue n cont1 ->
1654 case compare n len of
1655 EQ -> go (arr:backBuf) cont1 stream
1658 then yieldk backBuf cont1 arr stream
1661 bufLen = sum (Prelude.map GenArr.length backBuf)
1663 assertM(n1 >= 0 && n1 <= bufLen)
1664 let (s1, backBuf1) = backTrackGenericChunks n1 backBuf s
1665 go backBuf1 cont1 s1
1667 ParserK.Done n b -> do
1669 assertM(n1 <= sum (Prelude.map GenArr.length (arr:backBuf)))
1670 let (s1, _) = backTrackGenericChunks n1 (arr:backBuf) stream
1671 in return (Right b, s1)
1672 ParserK.Error _ err -> return (Left (ParseError err), nil)
1676 -> (ParserK.Input (GenArr.Array a)
1677 -> m (ParserK.Step (GenArr.Array a) m b))
1678 -> StreamK m (GenArr.Array a)
1679 -> m (Either ParseError b, StreamK m (GenArr.Array a))
1680 go backBuf parserk stream = do
1681 let stop = goStop backBuf parserk
1682 single a = yieldk backBuf parserk a nil
1684 defState (yieldk backBuf parserk) single stop stream
1686{-# INLINE parseChunksGeneric #-}
1687parseChunksGeneric ::
1689 => ParserK.ParserK (GenArr.Array a) m b
1690 -> StreamK m (GenArr.Array a)
1691 -> m (Either ParseError b)
1692parseChunksGeneric f = fmap fst . parseBreakChunksGeneric f
1694-------------------------------------------------------------------------------
1696-------------------------------------------------------------------------------
1698-- | Sort the input stream using a supplied comparison function.
1700-- Sorting can be achieved by simply:
1702-- >>> sortBy cmp = StreamK.mergeMapWith (StreamK.mergeBy cmp) StreamK.fromPure
1704-- However, this combinator uses a parser to first split the input stream into
1705-- down and up sorted segments and then merges them to optimize sorting when
1706-- pre-sorted sequences exist in the input stream.
1710{-# INLINE sortBy #-}
1711sortBy :: Monad m => (a -> a -> Ordering) -> StreamK m a -> StreamK m a
1712-- sortBy f = Stream.concatPairsWith (Stream.mergeBy f) Stream.fromPure
1715 Parser.groupByRollingEither
1716 (\x -> (< GT) . cmp x)
1719 in mergeMapWith (mergeBy cmp) id
1721 . Stream.catRights -- its a non-failing backtracking parser
1722 . Stream.parseMany (fmap (either id id) p)
1723 . Stream.fromStreamK
1725{-# INLINE sortOn #-}
1726sortOn :: (Monad m, Ord b) => (a -> b) -> StreamK m a -> StreamK m a
1729 . sortBy (comparing fst)
1730 . fmap (\x -> let y = f x in y `seq` (y, x))
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list