1{-# LANGUAGE BangPatterns #-}
3{-# LANGUAGE ConstraintKinds #-}
4{-# LANGUAGE FlexibleContexts #-}
5{-# LANGUAGE FlexibleInstances #-}
6{-# LANGUAGE InstanceSigs #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
8{-# LANGUAGE RankNTypes #-}
9{-# LANGUAGE ScopedTypeVariables #-}
10{-# LANGUAGE UndecidableInstances #-} -- XXX
15-- Module : Streamly.Streams.StreamK
16-- Copyright : (c) 2017 Harendra Kumar
19-- Maintainer : harendra.kumar@gmail.com
20-- Stability : experimental
24-- Continuation passing style (CPS) stream implementation. The symbol 'K' below
25-- denotes a function as well as a Kontinuation.
28-- import qualified Streamly.Streams.StreamK as K
31module Streamly.Streams.StreamK
33 -- * A class for streams
40 -- * Construction Primitives
46 -- * Elimination Primitives
51 -- * Transformation Primitives
62 -- ** Specialized Generation
84 -- ** Specialized Folds
113 -- ** By folding (scans)
147 -- ** Transformation comprehensions
150 -- * Semigroup Style Composition
159 , Streaming -- deprecated
164import Control.Monad (void)
165import Control.Monad.Reader.Class (MonadReader(..))
167 hiding (foldl, foldr, last, map, mapM, mapM_, repeat, sequence,
168 take, filter, all, any, takeWhile, drop, dropWhile, minimum,
169 maximum, elem, notElem, null, head, tail, init, zipWith, lookup,
170 foldr1, (!!), replicate)
171import qualified Prelude
174import Streamly.Streams.StreamK.Type
176-- | Detach a stream from an SVar
177{-# INLINE unShare #-}
178unShare :: IsStream t => t m a -> t m a
179unShare x = mkStream $ \st yld sng stp ->
180 foldStream st yld sng stp x
182------------------------------------------------------------------------------
184------------------------------------------------------------------------------
188-- faster than consM because there is no bind.
189-- | Construct a stream by adding a pure value at the head of an existing
190-- stream. For serial streams this is the same as @(return a) \`consM` r@ but
191-- more efficient. For concurrent streams this is not concurrent whereas
192-- 'consM' is concurrent. For example:
195-- > toList $ 1 \`cons` 2 \`cons` 3 \`cons` nil
201cons :: IsStream t => a -> t m a -> t m a
202cons a r = mkStream $ \_ yld _ _ -> yld a r
206-- | Operator equivalent of 'cons'.
209-- > toList $ 1 .: 2 .: 3 .: nil
215(.:) :: IsStream t => a -> t m a -> t m a
218-------------------------------------------------------------------------------
220-------------------------------------------------------------------------------
223uncons :: (IsStream t, Monad m) => t m a -> m (Maybe (a, t m a))
225 let stop = return Nothing
226 single a = return (Just (a, nil))
227 yieldk a r = return (Just (a, r))
228 in foldStream defState yieldk single stop m
230-------------------------------------------------------------------------------
232-------------------------------------------------------------------------------
234{-# INLINE_NORMAL build #-}
235build :: IsStream t => forall a. (forall b. (a -> b -> b) -> b -> b) -> t m a
238{-# INLINE_NORMAL _augment #-}
241 => forall a. (forall b. (a -> b -> b) -> b -> b) -> t m a -> t m a
242_augment g xs = g cons xs
244{-# INLINE_NORMAL _buildM #-}
246 :: (IsStream t, MonadAsync m)
247 => forall a. ((m a -> t m a -> t m a) -> t m a -> t m a) -> t m a
248_buildM g = g consM nil
250{-# INLINE unfoldr #-}
251unfoldr :: IsStream t => (b -> Maybe (a, b)) -> b -> t m a
252unfoldr step b0 = build $ \cns nl ->
255 Just (a, b) -> a `cns` go b
259{-# INLINE unfoldrM #-}
260unfoldrM :: (IsStream t, MonadAsync m) => (b -> m (Maybe (a, b))) -> b -> t m a
263 go s = mkStream $ \st yld sng stp -> do
268 foldStreamShared st yld sng stp $ return a |: go b
270-------------------------------------------------------------------------------
272-------------------------------------------------------------------------------
275yield :: IsStream t => a -> t m a
276yield a = mkStream $ \_ _ single _ -> single a
281{-# DEPRECATED once "Please use yieldM instead." #-}
283once :: (Monad m, IsStream t) => m a -> t m a
288-- repeatM = fix . cons
289-- repeatM = cycle1 . yield
292-- Generate an infinite stream by repeating a pure value.
296repeat :: IsStream t => a -> t m a
297repeat a = let x = cons a x in x
299{-# INLINE replicateM #-}
300replicateM :: (IsStream t, MonadAsync m) => Int -> m a -> t m a
303 go cnt = if cnt <= 0 then nil else m |: go (cnt - 1)
305{-# INLINE replicate #-}
306replicate :: IsStream t => Int -> a -> t m a
309 go cnt = if cnt <= 0 then nil else a `cons` go (cnt - 1)
311-------------------------------------------------------------------------------
313-------------------------------------------------------------------------------
317-- fromFoldable = 'Prelude.foldr' 'cons' 'nil'
320-- Construct a stream from a 'Foldable' containing pure values:
323{-# INLINE fromFoldable #-}
324fromFoldable :: (IsStream t, Foldable f) => f a -> t m a
325fromFoldable = Prelude.foldr cons nil
327{-# INLINE fromList #-}
328fromList :: IsStream t => [a] -> t m a
329fromList = fromFoldable
331{-# INLINE fromStreamK #-}
332fromStreamK :: IsStream t => Stream m a -> t m a
333fromStreamK = fromStream
335-------------------------------------------------------------------------------
336-- Elimination by Folding
337-------------------------------------------------------------------------------
339-- | Lazy right associative fold.
341foldr :: (IsStream t, Monad m) => (a -> b -> b) -> b -> t m a -> m b
342foldr step acc m = go m
345 let stop = return acc
346 single a = return (step a acc)
347 yieldk a r = go r >>= \b -> return (step a b)
348 in foldStream defState yieldk single stop m1
350-- | Lazy right fold with a monadic step function.
352foldrM :: (IsStream t, Monad m) => (a -> b -> m b) -> b -> t m a -> m b
353foldrM step acc m = go m
356 let stop = return acc
357 single a = step a acc
358 yieldk a r = go r >>= step a
359 in foldStream defState yieldk single stop m1
362foldr1 :: (IsStream t, Monad m) => (a -> a -> a) -> t m a -> m (Maybe a)
366 Nothing -> return Nothing
367 Just (h, t) -> fmap Just (go h t)
371 single a = return $ step a p
372 yieldk a r = fmap (step p) (go a r)
373 in foldStream defState yieldk single stp m1
375-- | Strict left fold with an extraction function. Like the standard strict
376-- left fold, but applies a user supplied extraction function (the third
377-- argument) to the folded value at the end. This is designed to work with the
378-- @foldl@ library. The suffix @x@ is a mnemonic for extraction.
380-- Note that the accumulator is always evaluated including the initial value.
382foldx :: forall t m a b x. (IsStream t, Monad m)
383 => (x -> a -> x) -> x -> (x -> b) -> t m a -> m b
384foldx step begin done m = get $ go m begin
389 -- XXX we are not strictly evaluating the accumulator here. Is this
391 let single = return . done
392 -- XXX this is foldSingleton. why foldStreamShared?
393 in foldStreamShared undefined undefined single undefined m1
395 -- Note, this can be implemented by making a recursive call to "go",
396 -- however that is more expensive because of unnecessary recursion
397 -- that cannot be tail call optimized. Unfolding recursion explicitly via
398 -- continuations is much more efficient.
399 go :: t m a -> x -> t m x
400 go m1 !acc = mkStream $ \_ yld sng _ ->
402 single a = sng $ step acc a
403 -- XXX this is foldNonEmptyStream
404 yieldk a r = foldStream defState yld sng undefined $
406 in foldStream defState yieldk single stop m1
408-- | Strict left associative fold.
410foldl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> m b
411foldl' step begin = foldx step begin id
413-- XXX replace the recursive "go" with explicit continuations.
414-- | Like 'foldx', but with a monadic step function.
415{-# INLINABLE foldxM #-}
416foldxM :: (IsStream t, Monad m)
417 => (x -> a -> m x) -> m x -> (x -> m b) -> t m a -> m b
418foldxM step begin done m = go begin m
421 let stop = acc >>= done
422 single a = acc >>= \b -> step b a >>= done
423 yieldk a r = acc >>= \b -> step b a >>= \x -> go (return x) r
424 in foldStream defState yieldk single stop m1
426-- | Like 'foldl'' but with a monadic step function.
427{-# INLINE foldlM' #-}
428foldlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> b -> t m a -> m b
429foldlM' step begin = foldxM step (return begin) return
431------------------------------------------------------------------------------
433------------------------------------------------------------------------------
436-- > runStream = foldl' (\_ _ -> ()) ()
437-- > runStream = mapM_ (\_ -> return ())
438{-# INLINE runStream #-}
439runStream :: (Monad m, IsStream t) => t m a -> m ()
446 in foldStream defState yieldk single stop m1
449null :: (IsStream t, Monad m) => t m a -> m Bool
451 let stop = return True
452 single _ = return False
453 yieldk _ _ = return False
454 in foldStream defState yieldk single stop m
457head :: (IsStream t, Monad m) => t m a -> m (Maybe a)
459 let stop = return Nothing
460 single a = return (Just a)
461 yieldk a _ = return (Just a)
462 in foldStream defState yieldk single stop m
465tail :: (IsStream t, Monad m) => t m a -> m (Maybe (t m a))
467 let stop = return Nothing
468 single _ = return $ Just nil
469 yieldk _ r = return $ Just r
470 in foldStream defState yieldk single stop m
473init :: (IsStream t, Monad m) => t m a -> m (Maybe (t m a))
479 Nothing -> return Nothing
480 Just (h, t) -> return . Just $ go h t
481 go p m1 = mkStream $ \_ yld sng stp ->
483 yieldk a x = yld p $ go a x
484 in foldStream defState yieldk single stp m1
487elem :: (IsStream t, Monad m, Eq a) => a -> t m a -> m Bool
491 let stop = return False
492 single a = return (a == e)
493 yieldk a r = if a == e then return True else go r
494 in foldStream defState yieldk single stop m1
496{-# INLINE notElem #-}
497notElem :: (IsStream t, Monad m, Eq a) => a -> t m a -> m Bool
501 let stop = return True
502 single a = return (a /= e)
503 yieldk a r = if a == e then return False else go r
504 in foldStream defState yieldk single stop m1
507all :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> m Bool
511 let single a | p a = return True
512 | otherwise = return False
513 yieldk a r | p a = go r
514 | otherwise = return False
515 in foldStream defState yieldk single (return True) m1
518any :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> m Bool
522 let single a | p a = return True
523 | otherwise = return False
524 yieldk a r | p a = return True
526 in foldStream defState yieldk single (return False) m1
528-- | Extract the last element of the stream, if any.
530last :: (IsStream t, Monad m) => t m a -> m (Maybe a)
531last = foldx (\_ y -> Just y) Nothing id
533{-# INLINE minimum #-}
534minimum :: (IsStream t, Monad m, Ord a) => t m a -> m (Maybe a)
535minimum m = go Nothing m
538 let stop = return Nothing
539 single a = return (Just a)
540 yieldk a r = go (Just a) r
541 in foldStream defState yieldk single stop m1
544 let stop = return (Just res)
547 then return (Just res)
553 in foldStream defState yieldk single stop m1
555{-# INLINE minimumBy #-}
557 :: (IsStream t, Monad m)
558 => (a -> a -> Ordering) -> t m a -> m (Maybe a)
559minimumBy cmp m = go Nothing m
562 let stop = return Nothing
563 single a = return (Just a)
564 yieldk a r = go (Just a) r
565 in foldStream defState yieldk single stop m1
568 let stop = return (Just res)
569 single a = case cmp res a of
570 GT -> return (Just a)
571 _ -> return (Just res)
572 yieldk a r = case cmp res a of
575 in foldStream defState yieldk single stop m1
577{-# INLINE maximum #-}
578maximum :: (IsStream t, Monad m, Ord a) => t m a -> m (Maybe a)
579maximum m = go Nothing m
582 let stop = return Nothing
583 single a = return (Just a)
584 yieldk a r = go (Just a) r
585 in foldStream defState yieldk single stop m1
588 let stop = return (Just res)
592 else return (Just res)
597 in foldStream defState yieldk single stop m1
599{-# INLINE maximumBy #-}
600maximumBy :: (IsStream t, Monad m) => (a -> a -> Ordering) -> t m a -> m (Maybe a)
601maximumBy cmp m = go Nothing m
604 let stop = return Nothing
605 single a = return (Just a)
606 yieldk a r = go (Just a) r
607 in foldStream defState yieldk single stop m1
610 let stop = return (Just res)
611 single a = case cmp res a of
612 GT -> return (Just res)
614 yieldk a r = case cmp res a of
615 GT -> go (Just res) r
617 in foldStream defState yieldk single stop m1
620(!!) :: (IsStream t, Monad m) => t m a -> Int -> m (Maybe a)
624 let single a | n == 0 = return $ Just a
625 | otherwise = return Nothing
626 yieldk a x | n < 0 = return Nothing
627 | n == 0 = return $ Just a
628 | otherwise = go (n - 1) x
629 in foldStream defState yieldk single (return Nothing) m1
632lookup :: (IsStream t, Monad m, Eq a) => a -> t m (a, b) -> m (Maybe b)
636 let single (a, b) | a == e = return $ Just b
637 | otherwise = return Nothing
638 yieldk (a, b) x | a == e = return $ Just b
640 in foldStream defState yieldk single (return Nothing) m1
643findM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> m (Maybe a)
649 if b then return $ Just a else return Nothing
652 if b then return $ Just a else go x
653 in foldStream defState yieldk single (return Nothing) m1
656find :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> m (Maybe a)
657find p = findM (return . p)
659{-# INLINE findIndices #-}
660findIndices :: IsStream t => (a -> Bool) -> t m a -> t m Int
663 go offset m1 = mkStream $ \st yld sng stp ->
664 let single a | p a = sng offset
666 yieldk a x | p a = yld offset $ go (offset + 1) x
667 | otherwise = foldStream (adaptState st) yld sng stp $
669 in foldStream (adaptState st) yieldk single stp m1
671------------------------------------------------------------------------------
673------------------------------------------------------------------------------
675-- | Apply a monadic action to each element of the stream and discard the
676-- output of the action.
678mapM_ :: (IsStream t, Monad m) => (a -> m b) -> t m a -> m ()
683 single a = void (f a)
684 yieldk a r = f a >> go r
685 in foldStream defState yieldk single stop m1
687------------------------------------------------------------------------------
689------------------------------------------------------------------------------
691{-# INLINABLE toList #-}
692toList :: (IsStream t, Monad m) => t m a -> m [a]
695{-# INLINE toStreamK #-}
696toStreamK :: Stream m a -> Stream m a
699-------------------------------------------------------------------------------
700-- Transformation by folding (Scans)
701-------------------------------------------------------------------------------
704scanx :: IsStream t => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
705scanx step begin done m =
706 cons (done begin) $ go m begin
708 go m1 !acc = mkStream $ \st yld sng stp ->
709 let single a = sng (done $ step acc a)
712 in yld (done s) (go r s)
713 in foldStream (adaptState st) yieldk single stp m1
716scanl' :: IsStream t => (b -> a -> b) -> b -> t m a -> t m b
717scanl' step begin = scanx step begin id
719-------------------------------------------------------------------------------
721-------------------------------------------------------------------------------
724filter :: IsStream t => (a -> Bool) -> t m a -> t m a
727 go m1 = mkStream $ \st yld sng stp ->
728 let single a | p a = sng a
730 yieldk a r | p a = yld a (go r)
731 | otherwise = foldStream st yieldk single stp r
732 in foldStream st yieldk single stp m1
735take :: IsStream t => Int -> t m a -> t m a
738 go n1 m1 = mkStream $ \st yld sng stp ->
739 let yieldk a r = yld a (go (n1 - 1) r)
742 else foldStream st yieldk sng stp m1
744{-# INLINE takeWhile #-}
745takeWhile :: IsStream t => (a -> Bool) -> t m a -> t m a
748 go m1 = mkStream $ \st yld sng stp ->
749 let single a | p a = sng a
751 yieldk a r | p a = yld a (go r)
753 in foldStream st yieldk single stp m1
756drop :: IsStream t => Int -> t m a -> t m a
759 go n1 m1 = mkStream $ \st yld sng stp ->
761 yieldk _ r = foldStream st yld sng stp $ go (n1 - 1) r
762 -- Somehow "<=" check performs better than a ">"
764 then foldStream st yld sng stp m1
765 else foldStream st yieldk single stp m1
767{-# INLINE dropWhile #-}
768dropWhile :: IsStream t => (a -> Bool) -> t m a -> t m a
771 go m1 = mkStream $ \st yld sng stp ->
772 let single a | p a = stp
774 yieldk a r | p a = foldStream st yieldk single stp r
775 | otherwise = yld a r
776 in foldStream st yieldk single stp m1
778-------------------------------------------------------------------------------
780-------------------------------------------------------------------------------
782-- Be careful when modifying this, this uses a consM (|:) deliberately to allow
783-- other stream types to overload it.
785mapM :: (IsStream t, MonadAsync m) => (a -> m b) -> t m a -> t m b
788 go m1 = mkStream $ \st yld sng stp ->
789 let single a = f a >>= sng
790 yieldk a r = foldStreamShared st yld sng stp $ f a |: go r
791 in foldStream (adaptState st) yieldk single stp m1
793-- Be careful when modifying this, this uses a consM (|:) deliberately to allow
794-- other stream types to overload it.
795{-# INLINE sequence #-}
796sequence :: (IsStream t, MonadAsync m) => t m (m a) -> t m a
799 go m1 = mkStream $ \st yld sng stp ->
800 let single ma = ma >>= sng
801 yieldk ma r = foldStreamShared st yld sng stp $ ma |: go r
802 in foldStream (adaptState st) yieldk single stp m1
804-------------------------------------------------------------------------------
806-------------------------------------------------------------------------------
808{-# INLINE intersperseM #-}
809intersperseM :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
810intersperseM a m = prependingStart m
812 prependingStart m1 = mkStream $ \st yld sng stp ->
813 let yieldk i x = foldStreamShared st yld sng stp $ return i |: go x
814 in foldStream st yieldk sng stp m1
815 go m2 = mkStream $ \st yld sng stp ->
816 let single i = foldStreamShared st yld sng stp $ a |: yield i
817 yieldk i x = foldStreamShared st yld sng stp $ a |: return i |: go x
818 in foldStream st yieldk single stp m2
820{-# INLINE insertBy #-}
821insertBy :: IsStream t => (a -> a -> Ordering) -> a -> t m a -> t m a
822insertBy cmp x m = go m
824 go m1 = mkStream $ \st yld _ _ ->
825 let single a = case cmp x a of
826 GT -> yld a (yield x)
829 yieldk a r = case cmp x a of
831 _ -> yld x (a `cons` r)
832 in foldStream st yieldk single stop m1
834------------------------------------------------------------------------------
836------------------------------------------------------------------------------
838{-# INLINE deleteBy #-}
839deleteBy :: IsStream t => (a -> a -> Bool) -> a -> t m a -> t m a
840deleteBy eq x m = go m
842 go m1 = mkStream $ \st yld sng stp ->
843 let single a = if eq x a then stp else sng a
844 yieldk a r = if eq x a
845 then foldStream st yld sng stp r
847 in foldStream st yieldk single stp m1
849-------------------------------------------------------------------------------
851-------------------------------------------------------------------------------
853{-# INLINE mapMaybe #-}
854mapMaybe :: IsStream t => (a -> Maybe b) -> t m a -> t m b
857 go m1 = mkStream $ \st yld sng stp ->
858 let single a = case f a of
861 yieldk a r = case f a of
862 Just b -> yld b $ go r
863 Nothing -> foldStream (adaptState st) yieldk single stp r
864 in foldStream (adaptState st) yieldk single stp m1
866------------------------------------------------------------------------------
868------------------------------------------------------------------------------
870-- | Zip two streams serially using a pure zipping function.
873{-# INLINABLE zipWith #-}
874zipWith :: IsStream t => (a -> b -> c) -> t m a -> t m b -> t m c
877 go mx my = mkStream $ \st yld sng stp -> do
879 let single2 b = sng (f a b)
880 yield2 b rb = yld (f a b) (go ra rb)
881 in foldStream (adaptState st) yield2 single2 stp my
882 let single1 a = merge a nil
884 foldStream (adaptState st) yield1 single1 stp mx
886-- | Zip two streams serially using a monadic zipping function.
889{-# INLINABLE zipWithM #-}
890zipWithM :: (IsStream t, Monad m) => (a -> b -> m c) -> t m a -> t m b -> t m c
891zipWithM f m1 m2 = go m1 m2
893 go mx my = mkStream $ \st yld sng stp -> do
895 let runIt x = foldStream st yld sng stp x
896 single2 b = f a b >>= sng
897 yield2 b rb = f a b >>= \x -> runIt (x `cons` go ra rb)
898 in foldStream (adaptState st) yield2 single2 stp my
899 let single1 a = merge a nil
901 foldStream (adaptState st) yield1 single1 stp mx
903------------------------------------------------------------------------------
905------------------------------------------------------------------------------
907{-# INLINE mergeByM #-}
909 :: (IsStream t, Monad m)
910 => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
913 go mx my = mkStream $ \st yld sng stp -> do
914 let mergeWithY a ra =
915 let stop2 = foldStream st yld sng stp mx
919 GT -> yld b (go (a `cons` ra) nil)
920 _ -> yld a (go ra (b `cons` nil))
924 GT -> yld b (go (a `cons` ra) rb)
925 _ -> yld a (go ra (b `cons` rb))
926 in foldStream st yield2 single2 stop2 my
927 let stopX = foldStream st yld sng stp my
928 singleX a = mergeWithY a nil
930 foldStream st yieldX singleX stopX mx
932{-# INLINABLE mergeBy #-}
934 :: (IsStream t, Monad m)
935 => (a -> a -> Ordering) -> t m a -> t m a -> t m a
936mergeBy cmp = mergeByM (\a b -> return $ cmp a b)
938------------------------------------------------------------------------------
939-- Transformation comprehensions
940------------------------------------------------------------------------------
943the :: (Eq a, IsStream t, Monad m) => t m a -> m (Maybe a)
947 Nothing -> return Nothing
948 Just (h, t) -> go h t
951 let single a | h == a = return $ Just h
952 | otherwise = return Nothing
953 yieldk a r | h == a = go h r
954 | otherwise = return Nothing
955 in foldStream defState yieldk single (return $ Just h) m1
957-------------------------------------------------------------------------------
959-------------------------------------------------------------------------------
961{-# INLINE bindWith #-}
964 => (forall c. t m c -> t m c -> t m c)
968bindWith par m1 f = go m1
971 mkStream $ \st yld sng stp ->
972 let foldShared = foldStreamShared st yld sng stp
973 single a = foldShared $ unShare (f a)
974 yieldk a r = foldShared $ unShare (f a) `par` go r
975 in foldStream (adaptState st) yieldk single stp m
977------------------------------------------------------------------------------
978-- Alternative & MonadPlus
979------------------------------------------------------------------------------
981_alt :: Stream m a -> Stream m a -> Stream m a
982_alt m1 m2 = mkStream $ \st yld sng stp ->
983 let stop = foldStream st yld sng stp m2
984 in foldStream st yld sng stop m1
986------------------------------------------------------------------------------
988------------------------------------------------------------------------------
990{-# INLINABLE withLocal #-}
991withLocal :: MonadReader r m => (r -> r) -> Stream m a -> Stream m a
993 mkStream $ \st yld sng stp ->
994 let single = local f . sng
995 yieldk a r = local f $ yld a (withLocal f r)
996 in foldStream st yieldk single (local f stp) m
998------------------------------------------------------------------------------
1000------------------------------------------------------------------------------
1003-- XXX handle and test cross thread state transfer
1006 => Stream m a -> (e -> Stream m a) -> Stream m a
1008 mkStream $ \_ stp sng yld ->
1009 let run x = unStream x Nothing stp sng yieldk
1010 handle r = r `catchError` \e -> run $ h e
1011 yieldk a r = yld a (withCatchError r h)
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