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
13-- Module : Streamly.Streams.StreamK
14-- Copyright : (c) 2017 Harendra Kumar
17-- Maintainer : harendra.kumar@gmail.com
18-- Stability : experimental
22-- Continuation passing style (CPS) stream implementation. The symbol 'K' below
23-- denotes a function as well as a Kontinuation.
26-- import qualified Streamly.Streams.StreamK as K
29module Streamly.Streams.StreamK
31 -- * A class for streams
38 -- * Construction Primitives
44 -- * Elimination Primitives
49 -- * Transformation Primitives
52 -- * Asynchronous construction
65 -- ** Specialized Generation
87 -- ** Specialized Folds
116 -- ** By folding (scans)
150 -- ** Transformation comprehensions
153 -- * Semigroup Style Composition
162 , Streaming -- deprecated
167import Control.Monad (void)
168import Control.Monad.Reader.Class (MonadReader(..))
170 hiding (foldl, foldr, last, map, mapM, mapM_, repeat, sequence,
171 take, filter, all, any, takeWhile, drop, dropWhile, minimum,
172 maximum, elem, notElem, null, head, tail, init, zipWith, lookup,
173 foldr1, (!!), replicate)
174import qualified Prelude
177import Streamly.Streams.StreamKType
179-- | Detach a stream from an SVar
180{-# INLINE unShare #-}
181unShare :: IsStream t => t m a -> t m a
182unShare x = mkStream $ \st stp sng yld ->
183 foldStream st stp sng yld x
185------------------------------------------------------------------------------
187------------------------------------------------------------------------------
191-- faster than consM because there is no bind.
192-- | Construct a stream by adding a pure value at the head of an existing
193-- stream. For serial streams this is the same as @(return a) \`consM` r@ but
194-- more efficient. For concurrent streams this is not concurrent whereas
195-- 'consM' is concurrent. For example:
198-- > toList $ 1 \`cons` 2 \`cons` 3 \`cons` nil
203cons :: IsStream t => a -> t m a -> t m a
204cons a r = mkStream $ \_ _ _ yld -> yld a r
208-- | Operator equivalent of 'cons'.
211-- > toList $ 1 .: 2 .: 3 .: nil
216(.:) :: IsStream t => a -> t m a -> t m a
219------------------------------------------------------------------------------
220-- Asynchronous construction
221------------------------------------------------------------------------------
223-- | Make an empty stream from a callback function.
224nilK :: IsStream t => (forall r. m r -> m r) -> t m a
225nilK k = mkStream $ \_ stp _ _ -> k stp
227-- | Make a singleton stream from a one shot callback function.
228yieldK :: IsStream t => (forall r. (a -> m r) -> m r) -> t m a
229yieldK k = mkStream $ \_ _ sng _ -> k sng
231-- | Construct a stream from a callback function.
232consK :: IsStream t => (forall r. (a -> m r) -> m r) -> t m a -> t m a
233consK k r = mkStream $ \_ _ _ yld -> k (\x -> yld x r)
235-- XXX consK with concurrent callbacks
236-- XXX Build a stream from a repeating callback function.
238-------------------------------------------------------------------------------
240-------------------------------------------------------------------------------
243uncons :: (IsStream t, Monad m) => t m a -> m (Maybe (a, t m a))
245 let stop = return Nothing
246 single a = return (Just (a, nil))
247 yieldk a r = return (Just (a, r))
248 in foldStream defState stop single yieldk m
250-------------------------------------------------------------------------------
252-------------------------------------------------------------------------------
254{-# INLINE unfoldr #-}
255unfoldr :: IsStream t => (b -> Maybe (a, b)) -> b -> t m a
258 go s = mkStream $ \_ stp _ yld ->
261 Just (a, b) -> yld a (go b)
263{-# INLINE unfoldrM #-}
264unfoldrM :: (IsStream t, MonadAsync m) => (b -> m (Maybe (a, b))) -> b -> t m a
267 go s = mkStream $ \st stp sng yld -> do
272 foldStreamShared st stp sng yld $ return a |: go b
274-------------------------------------------------------------------------------
276-------------------------------------------------------------------------------
278yield :: IsStream t => a -> t m a
279yield a = mkStream $ \_ _ single _ -> single a
284{-# DEPRECATED once "Please use yieldM instead." #-}
286once :: (Monad m, IsStream t) => m a -> t m a
291-- repeatM = fix . cons
292-- repeatM = cycle1 . yield
295-- Generate an infinite stream by repeating a pure value.
298repeat :: IsStream t => a -> t m a
299repeat a = let x = cons a x in x
301replicateM :: (IsStream t, MonadAsync m) => Int -> m a -> t m a
304 go cnt = if cnt <= 0 then nil else m |: go (cnt - 1)
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.
340foldr :: (IsStream t, Monad m) => (a -> b -> b) -> b -> t m a -> m b
341foldr step acc m = go m
344 let stop = return acc
345 single a = return (step a acc)
346 yieldk a r = go r >>= \b -> return (step a b)
347 in foldStream defState stop single yieldk m1
349-- | Lazy right fold with a monadic step function.
351foldrM :: (IsStream t, Monad m) => (a -> b -> m b) -> b -> t m a -> m b
352foldrM step acc m = go m
355 let stop = return acc
356 single a = step a acc
357 yieldk a r = go r >>= step a
358 in foldStream defState stop single yieldk m1
361foldr1 :: (IsStream t, Monad m) => (a -> a -> a) -> t m a -> m (Maybe a)
365 Nothing -> return Nothing
366 Just (h, t) -> fmap Just (go h t)
370 single a = return $ step a p
371 yieldk a r = fmap (step p) (go a r)
372 in foldStream defState stp single yieldk m1
374-- | Strict left fold with an extraction function. Like the standard strict
375-- left fold, but applies a user supplied extraction function (the third
376-- argument) to the folded value at the end. This is designed to work with the
377-- @foldl@ library. The suffix @x@ is a mnemonic for extraction.
379-- Note that the accumulator is always evaluated including the initial value.
381foldx :: forall t m a b x. (IsStream t, Monad m)
382 => (x -> a -> x) -> x -> (x -> b) -> t m a -> m b
383foldx step begin done m = get $ go m begin
388 -- XXX we are not strictly evaluating the accumulator here. Is this
390 let single = return . done
391 -- XXX this is foldSingleton. why foldStreamShared?
392 in foldStreamShared undefined undefined single undefined m1
394 -- Note, this can be implemented by making a recursive call to "go",
395 -- however that is more expensive because of unnecessary recursion
396 -- that cannot be tail call optimized. Unfolding recursion explicitly via
397 -- continuations is much more efficient.
398 go :: t m a -> x -> t m x
399 go m1 !acc = mkStream $ \_ _ sng yld ->
401 single a = sng $ step acc a
402 -- XXX this is foldNonEmptyStream
403 yieldk a r = foldStream defState undefined sng yld $
405 in foldStream defState stop single yieldk m1
407-- | Strict left associative fold.
409foldl' :: (IsStream t, Monad m) => (b -> a -> b) -> b -> t m a -> m b
410foldl' step begin = foldx step begin id
412-- XXX replace the recursive "go" with explicit continuations.
413-- | Like 'foldx', but with a monadic step function.
414foldxM :: (IsStream t, Monad m)
415 => (x -> a -> m x) -> m x -> (x -> m b) -> t m a -> m b
416foldxM step begin done m = go begin m
419 let stop = acc >>= done
420 single a = acc >>= \b -> step b a >>= done
421 yieldk a r = acc >>= \b -> step b a >>= \x -> go (return x) r
422 in foldStream defState stop single yieldk m1
424-- | Like 'foldl'' but with a monadic step function.
425foldlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> b -> t m a -> m b
426foldlM' step begin = foldxM step (return begin) return
428------------------------------------------------------------------------------
430------------------------------------------------------------------------------
432{-# INLINE runStream #-}
433runStream :: (Monad m, IsStream t) => t m a -> m ()
440 in foldStream defState stop single yieldk m1
443null :: (IsStream t, Monad m) => t m a -> m Bool
445 let stop = return True
446 single _ = return False
447 yieldk _ _ = return False
448 in foldStream defState stop single yieldk m
451head :: (IsStream t, Monad m) => t m a -> m (Maybe a)
453 let stop = return Nothing
454 single a = return (Just a)
455 yieldk a _ = return (Just a)
456 in foldStream defState stop single yieldk m
459tail :: (IsStream t, Monad m) => t m a -> m (Maybe (t m a))
461 let stop = return Nothing
462 single _ = return $ Just nil
463 yieldk _ r = return $ Just r
464 in foldStream defState stop single yieldk m
467init :: (IsStream t, Monad m) => t m a -> m (Maybe (t m a))
473 Nothing -> return Nothing
474 Just (h, t) -> return . Just $ go h t
475 go p m1 = mkStream $ \_ stp sng yld ->
477 yieldk a x = yld p $ go a x
478 in foldStream defState stp single yieldk m1
481elem :: (IsStream t, Monad m, Eq a) => a -> t m a -> m Bool
485 let stop = return False
486 single a = return (a == e)
487 yieldk a r = if a == e then return True else go r
488 in foldStream defState stop single yieldk m1
490{-# INLINE notElem #-}
491notElem :: (IsStream t, Monad m, Eq a) => a -> t m a -> m Bool
495 let stop = return True
496 single a = return (a /= e)
497 yieldk a r = if a == e then return False else go r
498 in foldStream defState stop single yieldk m1
500all :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> m Bool
504 let single a | p a = return True
505 | otherwise = return False
506 yieldk a r | p a = go r
507 | otherwise = return False
508 in foldStream defState (return True) single yieldk m1
510any :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> m Bool
514 let single a | p a = return True
515 | otherwise = return False
516 yieldk a r | p a = return True
518 in foldStream defState (return False) single yieldk m1
520-- | Extract the last element of the stream, if any.
522last :: (IsStream t, Monad m) => t m a -> m (Maybe a)
523last = foldx (\_ y -> Just y) Nothing id
525{-# INLINE minimum #-}
526minimum :: (IsStream t, Monad m, Ord a) => t m a -> m (Maybe a)
527minimum m = go Nothing m
530 let stop = return Nothing
531 single a = return (Just a)
532 yieldk a r = go (Just a) r
533 in foldStream defState stop single yieldk m1
536 let stop = return (Just res)
539 then return (Just res)
545 in foldStream defState stop single yieldk m1
547{-# INLINE minimumBy #-}
549 :: (IsStream t, Monad m)
550 => (a -> a -> Ordering) -> t m a -> m (Maybe a)
551minimumBy cmp m = go Nothing m
554 let stop = return Nothing
555 single a = return (Just a)
556 yieldk a r = go (Just a) r
557 in foldStream defState stop single yieldk m1
560 let stop = return (Just res)
561 single a = case cmp res a of
562 GT -> return (Just a)
563 _ -> return (Just res)
564 yieldk a r = case cmp res a of
567 in foldStream defState stop single yieldk m1
569{-# INLINE maximum #-}
570maximum :: (IsStream t, Monad m, Ord a) => t m a -> m (Maybe a)
571maximum m = go Nothing m
574 let stop = return Nothing
575 single a = return (Just a)
576 yieldk a r = go (Just a) r
577 in foldStream defState stop single yieldk m1
580 let stop = return (Just res)
584 else return (Just res)
589 in foldStream defState stop single yieldk m1
591{-# INLINE maximumBy #-}
592maximumBy :: (IsStream t, Monad m) => (a -> a -> Ordering) -> t m a -> m (Maybe a)
593maximumBy cmp m = go Nothing m
596 let stop = return Nothing
597 single a = return (Just a)
598 yieldk a r = go (Just a) r
599 in foldStream defState stop single yieldk m1
602 let stop = return (Just res)
603 single a = case cmp res a of
604 GT -> return (Just res)
606 yieldk a r = case cmp res a of
607 GT -> go (Just res) r
609 in foldStream defState stop single yieldk m1
612(!!) :: (IsStream t, Monad m) => t m a -> Int -> m (Maybe a)
616 let single a | n == 0 = return $ Just a
617 | otherwise = return Nothing
618 yieldk a x | n < 0 = return Nothing
619 | n == 0 = return $ Just a
620 | otherwise = go (n - 1) x
621 in foldStream defState (return Nothing) single yieldk m1
624lookup :: (IsStream t, Monad m, Eq a) => a -> t m (a, b) -> m (Maybe b)
628 let single (a, b) | a == e = return $ Just b
629 | otherwise = return Nothing
630 yieldk (a, b) x | a == e = return $ Just b
632 in foldStream defState (return Nothing) single yieldk m1
635findM :: (IsStream t, Monad m) => (a -> m Bool) -> t m a -> m (Maybe a)
641 if b then return $ Just a else return Nothing
644 if b then return $ Just a else go x
645 in foldStream defState (return Nothing) single yieldk m1
648find :: (IsStream t, Monad m) => (a -> Bool) -> t m a -> m (Maybe a)
649find p = findM (return . p)
651{-# INLINE findIndices #-}
652findIndices :: IsStream t => (a -> Bool) -> t m a -> t m Int
655 go offset m1 = mkStream $ \st stp sng yld ->
656 let single a | p a = sng offset
658 yieldk a x | p a = yld offset $ go (offset + 1) x
659 | otherwise = foldStream (adaptState st) stp sng yld $
661 in foldStream (adaptState st) stp single yieldk m1
663------------------------------------------------------------------------------
665------------------------------------------------------------------------------
667-- | Apply a monadic action to each element of the stream and discard the
668-- output of the action.
669mapM_ :: (IsStream t, Monad m) => (a -> m b) -> t m a -> m ()
674 single a = void (f a)
675 yieldk a r = f a >> go r
676 in foldStream defState stop single yieldk m1
678------------------------------------------------------------------------------
680------------------------------------------------------------------------------
682{-# INLINABLE toList #-}
683toList :: (IsStream t, Monad m) => t m a -> m [a]
686{-# INLINE toStreamK #-}
687toStreamK :: Stream m a -> Stream m a
690-------------------------------------------------------------------------------
691-- Transformation by folding (Scans)
692-------------------------------------------------------------------------------
695scanx :: IsStream t => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
696scanx step begin done m =
697 cons (done begin) $ go m begin
699 go m1 !acc = mkStream $ \st stp sng yld ->
700 let single a = sng (done $ step acc a)
703 in yld (done s) (go r s)
704 in foldStream (adaptState st) stp single yieldk m1
707scanl' :: IsStream t => (b -> a -> b) -> b -> t m a -> t m b
708scanl' step begin = scanx step begin id
710-------------------------------------------------------------------------------
712-------------------------------------------------------------------------------
715filter :: IsStream t => (a -> Bool) -> t m a -> t m a
718 go m1 = mkStream $ \st stp sng yld ->
719 let single a | p a = sng a
721 yieldk a r | p a = yld a (go r)
722 | otherwise = foldStream st stp single yieldk r
723 in foldStream st stp single yieldk m1
726take :: IsStream t => Int -> t m a -> t m a
729 go n1 m1 = mkStream $ \st stp sng yld ->
730 let yieldk a r = yld a (go (n1 - 1) r)
733 else foldStream st stp sng yieldk m1
735{-# INLINE takeWhile #-}
736takeWhile :: IsStream t => (a -> Bool) -> t m a -> t m a
739 go m1 = mkStream $ \st stp sng yld ->
740 let single a | p a = sng a
742 yieldk a r | p a = yld a (go r)
744 in foldStream st stp single yieldk m1
746drop :: IsStream t => Int -> t m a -> t m a
747drop n m = mkStream $ \st stp sng yld ->
748 foldStream st stp sng yld $ go n m
750 go n1 m1 = mkStream $ \st stp sng yld ->
752 yieldk _ r = foldStream st stp sng yld $ go (n1 - 1) r
753 -- Somehow "<=" check performs better than a ">"
755 then foldStream st stp sng yld m1
756 else foldStream st stp single yieldk m1
758{-# INLINE dropWhile #-}
759dropWhile :: IsStream t => (a -> Bool) -> t m a -> t m a
762 go m1 = mkStream $ \st stp sng yld ->
763 let single a | p a = stp
765 yieldk a r | p a = foldStream st stp single yieldk r
766 | otherwise = yld a r
767 in foldStream st stp single yieldk m1
769-------------------------------------------------------------------------------
771-------------------------------------------------------------------------------
773-- Be careful when modifying this, this uses a consM (|:) deliberately to allow
774-- other stream types to overload it.
776mapM :: (IsStream t, MonadAsync m) => (a -> m b) -> t m a -> t m b
779 go m1 = mkStream $ \st stp sng yld ->
780 let single a = f a >>= sng
781 yieldk a r = foldStreamShared st stp sng yld $ f a |: go r
782 in foldStream (adaptState st) stp single yieldk m1
784-- Be careful when modifying this, this uses a consM (|:) deliberately to allow
785-- other stream types to overload it.
786{-# INLINE sequence #-}
787sequence :: (IsStream t, MonadAsync m) => t m (m a) -> t m a
790 go m1 = mkStream $ \st stp sng yld ->
791 let single ma = ma >>= sng
792 yieldk ma r = foldStreamShared st stp sng yld $ ma |: go r
793 in foldStream (adaptState st) stp single yieldk m1
795-------------------------------------------------------------------------------
797-------------------------------------------------------------------------------
799{-# INLINE intersperseM #-}
800intersperseM :: (IsStream t, MonadAsync m) => m a -> t m a -> t m a
801intersperseM a m = prependingStart m
803 prependingStart m1 = mkStream $ \st stp sng yld ->
804 let yieldk i x = foldStreamShared st stp sng yld $ return i |: go x
805 in foldStream st stp sng yieldk m1
806 go m2 = mkStream $ \st stp sng yld ->
807 let single i = foldStreamShared st stp sng yld $ a |: yield i
808 yieldk i x = foldStreamShared st stp sng yld $ a |: return i |: go x
809 in foldStream st stp single yieldk m2
811{-# INLINE insertBy #-}
812insertBy :: IsStream t => (a -> a -> Ordering) -> a -> t m a -> t m a
813insertBy cmp x m = go m
815 go m1 = mkStream $ \st _ _ yld ->
816 let single a = case cmp x a of
817 GT -> yld a (yield x)
820 yieldk a r = case cmp x a of
822 _ -> yld x (a `cons` r)
823 in foldStream st stop single yieldk m1
825------------------------------------------------------------------------------
827------------------------------------------------------------------------------
829{-# INLINE deleteBy #-}
830deleteBy :: IsStream t => (a -> a -> Bool) -> a -> t m a -> t m a
831deleteBy eq x m = go m
833 go m1 = mkStream $ \st stp sng yld ->
834 let single a = if eq x a then stp else sng a
835 yieldk a r = if eq x a
836 then foldStream st stp sng yld r
838 in foldStream st stp single yieldk m1
840-------------------------------------------------------------------------------
842-------------------------------------------------------------------------------
844{-# INLINE mapMaybe #-}
845mapMaybe :: IsStream t => (a -> Maybe b) -> t m a -> t m b
848 go m1 = mkStream $ \st stp sng yld ->
849 let single a = case f a of
852 yieldk a r = case f a of
853 Just b -> yld b $ go r
854 Nothing -> foldStream (adaptState st) stp single yieldk r
855 in foldStream (adaptState st) stp single yieldk m1
857------------------------------------------------------------------------------
859------------------------------------------------------------------------------
861-- | Zip two streams serially using a pure zipping function.
864{-# INLINABLE zipWith #-}
865zipWith :: IsStream t => (a -> b -> c) -> t m a -> t m b -> t m c
868 go mx my = mkStream $ \st stp sng yld -> do
870 let single2 b = sng (f a b)
871 yield2 b rb = yld (f a b) (go ra rb)
872 in foldStream (adaptState st) stp single2 yield2 my
873 let single1 a = merge a nil
875 foldStream (adaptState st) stp single1 yield1 mx
877-- | Zip two streams serially using a monadic zipping function.
880zipWithM :: (IsStream t, Monad m) => (a -> b -> m c) -> t m a -> t m b -> t m c
881zipWithM f m1 m2 = go m1 m2
883 go mx my = mkStream $ \st stp sng yld -> do
885 let runIt x = foldStream st stp sng yld x
886 single2 b = f a b >>= sng
887 yield2 b rb = f a b >>= \x -> runIt (x `cons` go ra rb)
888 in foldStream (adaptState st) stp single2 yield2 my
889 let single1 a = merge a nil
891 foldStream (adaptState st) stp single1 yield1 mx
893------------------------------------------------------------------------------
895------------------------------------------------------------------------------
897{-# INLINE mergeByM #-}
899 :: (IsStream t, Monad m)
900 => (a -> a -> m Ordering) -> t m a -> t m a -> t m a
903 go mx my = mkStream $ \st stp sng yld -> do
904 let mergeWithY a ra =
905 let stop2 = foldStream st stp sng yld mx
909 GT -> yld b (go (a `cons` ra) nil)
910 _ -> yld a (go ra (b `cons` nil))
914 GT -> yld b (go (a `cons` ra) rb)
915 _ -> yld a (go ra (b `cons` rb))
916 in foldStream st stop2 single2 yield2 my
917 let stopX = foldStream st stp sng yld my
918 singleX a = mergeWithY a nil
920 foldStream st stopX singleX yieldX mx
922{-# INLINABLE mergeBy #-}
924 :: (IsStream t, Monad m)
925 => (a -> a -> Ordering) -> t m a -> t m a -> t m a
926mergeBy cmp = mergeByM (\a b -> return $ cmp a b)
928------------------------------------------------------------------------------
929-- Transformation comprehensions
930------------------------------------------------------------------------------
933the :: (Eq a, IsStream t, Monad m) => t m a -> m (Maybe a)
937 Nothing -> return Nothing
938 Just (h, t) -> go h t
941 let single a | h == a = return $ Just h
942 | otherwise = return Nothing
943 yieldk a r | h == a = go h r
944 | otherwise = return Nothing
945 in foldStream defState (return $ Just h) single yieldk m1
947-------------------------------------------------------------------------------
949-------------------------------------------------------------------------------
951{-# INLINE bindWith #-}
954 => (forall c. t m c -> t m c -> t m c)
958bindWith par m1 f = go m1
961 mkStream $ \st stp sng yld ->
962 let foldShared = foldStreamShared st stp sng yld
963 single a = foldShared $ unShare (f a)
964 yieldk a r = foldShared $ unShare (f a) `par` go r
965 in foldStream (adaptState st) stp single yieldk m
967------------------------------------------------------------------------------
968-- Alternative & MonadPlus
969------------------------------------------------------------------------------
971_alt :: Stream m a -> Stream m a -> Stream m a
972_alt m1 m2 = mkStream $ \st stp sng yld ->
973 let stop = foldStream st stp sng yld m2
974 in foldStream st stop sng yld m1
976------------------------------------------------------------------------------
978------------------------------------------------------------------------------
980withLocal :: MonadReader r m => (r -> r) -> Stream m a -> Stream m a
982 mkStream $ \st stp sng yld ->
983 let single = local f . sng
984 yieldk a r = local f $ yld a (withLocal f r)
985 in foldStream st (local f stp) single yieldk m
987------------------------------------------------------------------------------
989------------------------------------------------------------------------------
992-- XXX handle and test cross thread state transfer
995 => Stream m a -> (e -> Stream m a) -> Stream m a
997 mkStream $ \_ stp sng yld ->
998 let run x = unStream x Nothing stp sng yieldk
999 handle r = r `catchError` \e -> run $ h e
1000 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