@@ -524,26 +524,58 @@ tailPartial m = mkStream $ \st yld sng stp ->
524 yieldk _ r = foldStream st yld sng stp r
524 yieldk _ r = foldStream st yld sng stp r
525 in foldStream st yieldk single stop m
525 in foldStream st yieldk single stop m
527−-- | Iterate a lazy function `f` of the shape `m a -> t m a` until it gets
527+-- | We can define cyclic structures using @let@:
528−-- fully defined i.e. becomes independent of its argument action, then return
529−-- the resulting value of the function (`t m a`).
531−-- It can be used to construct a stream that uses a cyclic definition. For
529+-- >>> let (a, b) = ([1, b], head a) in (a, b)
532−-- example:
530+-- ([1,1],1)
532+-- The function @fix@ defined as:
534+-- > fix f = let x = f x in x
536+-- ensures that the argument of a function and its output refer to the same
537+-- lazy value @x@ i.e. the same location in memory. Thus @x@ can be defined
538+-- in terms of itself, creating structures with cyclic references.
540+-- >>> f ~(a, b) = ([1, b], head a)
544+-- 'Control.Monad.mfix' is essentially the same as @fix@ but for monadic
547+-- Using 'mfix' for streams we can construct a stream in which each element of
548+-- the stream is defined in a cyclic fashion. The argument of the function
549+-- being fixed represents the current element of the stream which is being
550+-- returned by the stream monad. Thus, we can use the argument to construct
553+-- In the following example, the argument @action@ of the function @f@
554+-- represents the tuple @(x,y)@ returned by it in a given iteration. We define
555+-- the first element of the tuple in terms of the second.
535−-- import Streamly.Internal.Data.Stream.IsStream as S
558+-- import Streamly.Internal.Data.Stream.IsStream as Stream
536-- import System.IO.Unsafe (unsafeInterleaveIO)
559-- import System.IO.Unsafe (unsafeInterleaveIO)
538-- main = do
561-- main = do
539−-- S.mapM_ print $ S.mfix $ \x -> do
562+-- Stream.mapM_ print $ Stream.mfix f
540−-- a <- S.fromList [1,2]
563+--
541−-- b <- S.fromListM [return 3, unsafeInterleaveIO (fmap fst x)]
564+-- where
567+-- let incr n act = fmap ((+n) . snd) $ unsafeInterleaveIO act
568+-- x <- Stream.fromListM [incr 1 action, incr 2 action]
569+-- y <- Stream.fromList [4,5]
542−-- return (a, b)
570+-- return (x, y)
573+-- Note: you cannot achieve this by just changing the order of the monad
574+-- statements because that would change the order in which the stream elements
545−-- Note that the function `f` must be lazy in its argument, that's why we use
577+-- Note that the function @f@ must be lazy in its argument, that's why we use
546−-- 'unsafeInterleaveIO' because IO monad is strict.
578+-- 'unsafeInterleaveIO' on @action@ because IO monad is strict.
548-- /Internal/
580-- /Internal/
@@ -552,8 +584,14 @@ mfix f = mkStream $ \st yld sng stp ->
552 let single a = foldStream st yld sng stp $ a `cons` ys
584 let single a = foldStream st yld sng stp $ a `cons` ys
553 yieldk a _ = foldStream st yld sng stp $ a `cons` ys
585 yieldk a _ = foldStream st yld sng stp $ a `cons` ys
554 in foldStream st yieldk single stp xs
586 in foldStream st yieldk single stp xs
590+ -- fix the head element of the stream
555− where xs = fix (f . headPartial)
591+ xs = fix (f . headPartial)
593+ -- now fix the tail recursively
556− ys = mfix (tailPartial . f)
594+ ys = mfix (tailPartial . f)
558{-# INLINE init #-}
596{-# INLINE init #-}
559init :: (IsStream t, Monad m) => t m a -> m (Maybe (t m a))
597init :: (IsStream t, Monad m) => t m a -> m (Maybe (t m a))