on master help sign in
Update Unfold docs, expose doctest setup
019d0c9Harendra Kumar
core/src/DocTestDataUnfold.hsnew file+12
@@ -0,0 +1,12 @@
1+{- $setup
2+
3+>>> :m
4+>>> import Streamly.Data.Unfold (Unfold)
5+>>> import qualified Streamly.Data.Fold as Fold
6+>>> import qualified Streamly.Data.Stream as Stream
7+>>> import qualified Streamly.Data.Unfold as Unfold
8+
9+For APIs that have not been released yet.
10+
11+>>> import qualified Streamly.Internal.Data.Unfold as Unfold
12+-}
core/src/Streamly/Data/Unfold.hs+93−85
@@ -1,4 +1,4 @@
1−#include "inline.hs"
1+{-# LANGUAGE CPP #-}
2
2
3-- |
3-- |
4-- Module : Streamly.Data.Unfold
4-- Module : Streamly.Data.Unfold
@@ -8,13 +8,99 @@
8-- Stability : released
8-- Stability : released
9-- Portability : GHC
9-- Portability : GHC
10--
10--
11+-- Fast, composable stream producers with ability to terminate, supporting
12+-- nested stream fusion. Nested stream operations like
13+-- 'Streamly.Data.Stream.concatMap' in the "Streamly.Data.Stream" module do not
14+-- fuse, however, the 'Streamly.Data.Stream.unfoldMany' operation, using the
15+-- 'Unfold' type, is a fully fusible alternative to
16+-- 'Streamly.Data.Stream.concatMap'.
17+--
18+-- Please refer to "Streamly.Internal.Data.Unfold" for more functions that have
19+-- not yet been released.
20+--
21+-- Exception combinators are not exposed, we would like to encourage the use of
22+-- 'Stream' type instead whenever exception handling is required. We can
23+-- consider exposing the unfold exception functions if there is a compelling
24+-- use case to use unfolds instead of stream.
25+
26+module Streamly.Data.Unfold
27+ (
28+ -- * Setup
29+ -- | To execute the code examples provided in this module in ghci, please
30+ -- run the following commands first.
31+ --
32+ -- $setup
33+
34+ -- * Overview
35+ -- $overview
36+
37+ -- * Unfold Type
38+ Unfold
39+
40+ -- * Unfolds
41+ -- One to one correspondence with
42+ -- "Streamly.Internal.Data.Stream.Generate"
43+
44+ -- ** Basic Constructors
45+ , unfoldrM
46+ , unfoldr
47+ , function
48+ , functionM
49+
50+ -- ** Generators
51+ -- | Generate a monadic stream from a seed.
52+ , repeatM
53+ , replicateM
54+ , iterateM
55+
56+ -- ** From Containers
57+ , fromList
58+ , fromListM
59+ , fromStream
60+
61+ -- * Combinators
62+ -- ** Mapping on Input
63+ , lmap
64+ , lmapM
65+
66+ -- ** Mapping on Output
67+ , mapM
68+
69+ -- ** Filtering
70+ , takeWhileM
71+ , takeWhile
72+ , take
73+ , filter
74+ , filterM
75+ , drop
76+ , dropWhile
77+ , dropWhileM
78+
79+ -- ** Zipping
80+ , zipWith
81+
82+ -- ** Cross Product
83+ , crossWith
84+
85+ -- ** Nesting
86+ , many
87+
88+ )
89+where
90+
91+import Prelude hiding
92+ ( concat, map, mapM, takeWhile, take, filter, const, drop, dropWhile
93+ , zipWith
94+ )
95+import Streamly.Internal.Data.Unfold
96+
97+#include "DocTestDataUnfold.hs"
98+
99+-- $overview
100+--
11-- An 'Unfold' is a source or a producer of a stream of values. It takes a
101-- An 'Unfold' is a source or a producer of a stream of values. It takes a
12-- seed value as an input and unfolds it into a sequence of values.
102-- seed value as an input and unfolds it into a sequence of values.
13--
103--
14−-- >>> import qualified Streamly.Data.Fold as Fold
15−-- >>> import qualified Streamly.Data.Unfold as Unfold
16−-- >>> import qualified Streamly.Internal.Data.Stream as Stream
17−--
18-- For example, the 'fromList' Unfold generates a stream of values from a
104-- For example, the 'fromList' Unfold generates a stream of values from a
19-- supplied list. Unfolds can be converted to 'Streamly.Internal.Data.Stream'
105-- supplied list. Unfolds can be converted to 'Streamly.Internal.Data.Stream'
20-- using the 'Stream.unfold' operation.
106-- using the 'Stream.unfold' operation.
@@ -58,7 +144,7 @@
58-- Please see "Streamly.Internal.Data.Unfold" for additional @Pre-release@
144-- Please see "Streamly.Internal.Data.Unfold" for additional @Pre-release@
59-- functions.
145-- functions.
60--
146--
61−-- = Creating New Unfolds
147+-- == Creating New Unfolds
62--
148--
63-- There are many commonly used unfolds provided in this module. However, you
149-- There are many commonly used unfolds provided in this module. However, you
64-- can always create your own as well. An 'Unfold' is just a data
150-- can always create your own as well. An 'Unfold' is just a data
@@ -95,7 +181,7 @@
95-- >>> Data.List.unfoldr f [1,2,3]
181-- >>> Data.List.unfoldr f [1,2,3]
96-- [1,2,3]
182-- [1,2,3]
97--
183--
98−-- = Unfolds vs. Streams
184+-- == Unfolds vs. Streams
99--
185--
100-- The 'Unfold' abstraction for representing streams was introduced in Streamly
186-- The 'Unfold' abstraction for representing streams was introduced in Streamly
101-- to provide C like performance for nested looping of streams. 'Unfold' and
187-- to provide C like performance for nested looping of streams. 'Unfold' and
@@ -140,81 +226,3 @@
140-- streams are written, it is easy to adapt a stream to an unfold. If you are
226-- streams are written, it is easy to adapt a stream to an unfold. If you are
141-- writing an unfold you can convert it to stream for free using
227-- writing an unfold you can convert it to stream for free using
142-- 'Stream.unfold'.
228-- 'Stream.unfold'.
143−
144−-- What makes streams less efficient is also what makes them more conveient to
145−-- use and powerful. The stream data type (Stream m a) bundles the state along
146−-- with the stream generator function making it opaque, whereas an unfold
147−-- exposes the state (Unfold m s a) to the user. This allows the Unfold to be
148−-- unfolded (inlined) inside a nested loop without having to bundle the state
149−-- and the generator together, the stream state can be saved and passed
150−-- independent of the generator function. On the other hand in a stream type we
151−-- have to bundle the stream state and the generator function together to save
152−-- the stream. This makes it inefficient because it requires boxing and
153−-- constructor allocation. However, this makes streams more convenient as we do
154−-- not need to pass around the state/seed separately.
155−--
156−module Streamly.Data.Unfold
157− (
158− -- * Unfold Type
159− Unfold
160−
161− -- * Unfolds
162− -- One to one correspondence with
163− -- "Streamly.Internal.Data.Stream.Generate"
164−
165− -- ** Basic Constructors
166− , unfoldrM
167− , unfoldr
168− , function
169− , functionM
170−
171− -- ** Generators
172− -- | Generate a monadic stream from a seed.
173− , repeatM
174− , replicateM
175− , iterateM
176−
177− -- ** From Containers
178− , fromList
179− , fromListM
180− , fromStream
181−
182− -- * Combinators
183− -- ** Mapping on Input
184− , lmap
185− , lmapM
186−
187− -- ** Mapping on Output
188− , mapM
189−
190− -- ** Filtering
191− , takeWhileM
192− , takeWhile
193− , take
194− , filter
195− , filterM
196− , drop
197− , dropWhile
198− , dropWhileM
199−
200− -- ** Zipping
201− , zipWith
202−
203− -- ** Cross Product
204− , crossWith
205−
206− -- ** Nesting
207− , many
208−
209− -- Exception combinators are not exposed, we would like to encourage the
210− -- use of Stream type instead where exception handling is required. We can
211− -- consider exposing the unfold exception functions if there is a
212− -- compelling use case to use unfolds instead of stream.
213− )
214−where
215−
216−import Prelude hiding
217− ( concat, map, mapM, takeWhile, take, filter, const, drop, dropWhile
218− , zipWith
219− )
220−import Streamly.Internal.Data.Unfold
core/src/Streamly/Internal/Data/Unfold.hs+8−107
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
1-- |
2-- |
2-- Module : Streamly.Internal.Data.Unfold
3-- Module : Streamly.Internal.Data.Unfold
3-- Copyright : (c) 2019 Composewell Technologies
4-- Copyright : (c) 2019 Composewell Technologies
@@ -6,110 +7,14 @@
6-- Stability : experimental
7-- Stability : experimental
7-- Portability : GHC
8-- Portability : GHC
8--
9--
9−-- To run the examples in this module:
10−--
11−-- >>> import qualified Streamly.Data.Fold as Fold
12−-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
13−--
14−-- = Unfolds and Streams
15−--
16−-- An 'Unfold' type is the same as the direct style 'Stream' type except that
17−-- it uses an inject function to determine the initial state of the stream
18−-- based on an input. A stream is a special case of Unfold when the static
19−-- input is unit or Void.
20−--
21−-- This allows an important optimization to occur in several cases, making the
22−-- 'Unfold' a more efficient abstraction. Consider the 'concatMap' and
23−-- 'unfoldMany' operations, the latter is more efficient. 'concatMap'
24−-- generates a new stream object from each element in the stream by applying
25−-- the supplied function to the element, the stream object includes the "step"
26−-- function as well as the initial "state" of the stream. Since the stream is
27−-- generated dynamically the compiler does not know the step function or the
28−-- state type statically at compile time, therefore, it cannot inline it. On
29−-- the other hand in case of 'unfoldMany' the compiler has visibility into
30−-- the unfold's state generation function, therefore, the compiler knows all
31−-- the types statically and it can inline the inject as well as the step
32−-- functions, generating efficient code. Essentially, the stream is not opaque
33−-- to the consumer in case of unfolds, the consumer knows how to generate the
34−-- stream from a seed using a known "inject" and "step" functions.
35−--
36−-- A Stream is like a data object whereas unfold is like a function. Being
37−-- function like, an Unfold is an instance of 'Category' and 'Arrow' type
38−-- classes.
39−--
40−-- = Unfolds and Folds
41−--
42−-- Streams forcing a closed control flow loop can be categorized under
43−-- two types, unfolds and folds, both of these are duals of each other.
44−--
45−-- Unfold streams are really generators of a sequence of elements, we can also
46−-- call them pull style streams. These are lazy producers of streams. On each
47−-- evaluation the producer generates the next element. A consumer can
48−-- therefore pull elements from the stream whenever it wants to. A stream
49−-- consumer can multiplex pull streams by pulling elements from the chosen
50−-- streams, therefore, pull streams allow merging or multiplexing. On the
51−-- other hand, with this representation we cannot split or demultiplex a
52−-- stream. So really these are stream sources that can be generated from a
53−-- seed and can be merged or zipped into a single stream.
54−--
55−-- The dual of Unfolds are Folds. Folds can also be called as push style
56−-- streams or reducers. These are strict consumers of streams. We keep pushing
57−-- elements to a fold and we can extract the result at any point. A driver can
58−-- choose which fold to push to and can also push the same element to multiple
59−-- folds. Therefore, folds allow splitting or demultiplexing a stream. On the
60−-- other hand, we cannot merge streams using this representation. So really
61−-- these are stream consumers that reduce the stream to a single value, these
62−-- consumers can be composed such that a stream can be split over multiple
63−-- consumers.
64−--
65−-- Performance:
66−--
67−-- Composing a tree or graph of computations with unfolds can be much more
68−-- efficient compared to composing with the Monad instance. The reason is that
69−-- unfolds allow the compiler to statically know the state and optimize it
70−-- using stream fusion whereas it is not possible with the monad bind because
71−-- the state is determined dynamically.
72−--
73−-- Reader:
74−--
75−-- An unfold acts as a reader (see 'Reader' monad). The input to an unfold acts
76−-- as the read-only environment. The environment can be extracted using the
77−-- 'identity' unfold (equivalent to 'ask') and transformed using 'lmap'.
78−
79−-- Open control flow style streams can also have two representations. StreamK
80−-- is a producer style representation. We can also have a consumer style
81−-- representation. We can use that for composable folds in StreamK
82−-- representation.
83−--
84−
85−-- = Performance Notes
86−--
87−-- 'Unfold' representation is more efficient than using streams when combining
88−-- streams. 'Unfold' type allows multiple unfold actions to be composed into a
89−-- single unfold function in an efficient manner by enabling the compiler to
90−-- perform stream fusion optimization.
91−-- @Unfold m a b@ can be considered roughly equivalent to an action @a -> t m
92−-- b@ (where @t@ is a stream type). Instead of using an 'Unfold' one could just
93−-- use a function of the shape @a -> t m b@. However, working with stream types
94−-- like t'Streamly.SerialT' does not allow the compiler to perform stream fusion
95−-- optimization when merging, appending or concatenating multiple streams.
96−-- Even though stream based combinator have excellent performance, they are
97−-- much less efficient when compared to combinators using 'Unfold'. For
98−-- example, the 'Streamly.Data.Stream.concatMap' combinator which uses @a -> t m b@
99−-- (where @t@ is a stream type) to generate streams is much less efficient
100−-- compared to 'Streamly.Data.Stream.unfoldMany'.
101−--
102−-- On the other hand, transformation operations on stream types are as
103−-- efficient as transformations on 'Unfold'.
104−--
105−-- We should note that in some cases working with stream types may be more
106−-- convenient compared to working with the 'Unfold' type. However, if extra
107−-- performance boost is important then 'Unfold' based composition should be
108−-- preferred compared to stream based composition when merging or concatenating
109−-- streams.
110−
111module Streamly.Internal.Data.Unfold
10module Streamly.Internal.Data.Unfold
112 (
11 (
12+ -- * Setup
13+ -- | To execute the code examples provided in this module in ghci, please
14+ -- run the following commands first.
15+ --
16+ -- $setup
17+
113 -- * Unfold Type
18 -- * Unfold Type
114 Step(..)
19 Step(..)
115 , Unfold
20 , Unfold
@@ -303,11 +208,7 @@ import Control.Monad.IO.Class (MonadIO (liftIO))
303import Foreign (Storable, peek, sizeOf)
208import Foreign (Storable, peek, sizeOf)
304import Foreign.Ptr
209import Foreign.Ptr
305
210
306−-- $setup
211+#include "DocTestDataUnfold.hs"
307−-- >>> import qualified Streamly.Data.Fold as Fold
308−-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
309−-- >>> import qualified Streamly.Data.Stream as Stream
310−
311
212
312-- | Convert an 'Unfold' into an unfold accepting a tuple as an argument,
213-- | Convert an 'Unfold' into an unfold accepting a tuple as an argument,
313-- using the argument of the original fold as the second element of tuple and
214-- using the argument of the original fold as the second element of tuple and
core/src/Streamly/Internal/Data/Unfold/Type.hs+130−19
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
1-- |
2-- |
2-- Module : Streamly.Internal.Data.Unfold.Type
3-- Module : Streamly.Internal.Data.Unfold.Type
3-- Copyright : (c) 2019 Composewell Technologies
4-- Copyright : (c) 2019 Composewell Technologies
@@ -6,14 +7,49 @@
6-- Stability : experimental
7-- Stability : experimental
7-- Portability : GHC
8-- Portability : GHC
8--
9--
9−-- To run the examples in this module:
10+-- An unfold is akin to a reader. It is the streaming equivalent of a reader.
10−--
11+-- The argument @a@ is the environment of the reader. That's the reason the
11−-- >>> import qualified Streamly.Data.Stream as Stream
12+-- default unfolds in various modules are named "reader".
12−-- >>> import qualified Streamly.Data.Fold as Fold
13+
13−-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
14+-- = Performance Notes
15+--
16+-- 'Unfold' representation is more efficient than using streams when combining
17+-- streams. 'Unfold' type allows multiple unfold actions to be composed into a
18+-- single unfold function in an efficient manner by enabling the compiler to
19+-- perform stream fusion optimization.
20+-- @Unfold m a b@ can be considered roughly equivalent to an action @a -> t m
21+-- b@ (where @t@ is a stream type). Instead of using an 'Unfold' one could just
22+-- use a function of the shape @a -> t m b@. However, working with stream types
23+-- like t'Streamly.SerialT' does not allow the compiler to perform stream fusion
24+-- optimization when merging, appending or concatenating multiple streams.
25+-- Even though stream based combinator have excellent performance, they are
26+-- much less efficient when compared to combinators using 'Unfold'. For
27+-- example, the 'Streamly.Data.Stream.concatMap' combinator which uses @a -> t m b@
28+-- (where @t@ is a stream type) to generate streams is much less efficient
29+-- compared to 'Streamly.Data.Stream.unfoldMany'.
30+--
31+-- On the other hand, transformation operations on stream types are as
32+-- efficient as transformations on 'Unfold'.
33+--
34+-- We should note that in some cases working with stream types may be more
35+-- convenient compared to working with the 'Unfold' type. However, if extra
36+-- performance boost is important then 'Unfold' based composition should be
37+-- preferred compared to stream based composition when merging or concatenating
38+-- streams.
14
39
15module Streamly.Internal.Data.Unfold.Type
40module Streamly.Internal.Data.Unfold.Type
41+ (
42+ -- * Setup
43+ -- | To execute the code examples provided in this module in ghci, please
44+ -- run the following commands first.
45+ --
46+ -- $setup
47+
48+ -- * General Notes
49+ -- $notes
50+
51+ -- * Type
16− ( Unfold (..)
52+ Unfold (..)
17
53
18 -- * Basic Constructors
54 -- * Basic Constructors
19 , mkUnfoldM
55 , mkUnfoldM
@@ -84,22 +120,96 @@ import Streamly.Internal.Data.Stream.StreamD.Step (Step(..))
84
120
85import Prelude hiding (map, mapM, concatMap, zipWith, takeWhile)
121import Prelude hiding (map, mapM, concatMap, zipWith, takeWhile)
86
122
87−-- $setup
123+#include "DocTestDataUnfold.hs"
88−-- >>> import qualified Streamly.Data.Stream as Stream
124+
89−-- >>> import qualified Streamly.Data.Fold as Fold
125+-- $notes
90−-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
126+--
127+-- What makes streams less efficient is also what makes them more convenient to
128+-- use and powerful. The stream data type (Stream m a) bundles the state along
129+-- with the stream generator function making it opaque, whereas an unfold
130+-- exposes the state (Unfold m s a) to the user. This allows the Unfold to be
131+-- unfolded (inlined) inside a nested loop without having to bundle the state
132+-- and the generator together, the stream state can be saved and passed
133+-- independent of the generator function. On the other hand in a stream type we
134+-- have to bundle the stream state and the generator function together to save
135+-- the stream. This makes it inefficient because it requires boxing and
136+-- constructor allocation. However, this makes streams more convenient as we do
137+-- not need to pass around the state/seed separately.
138+--
139+-- Unfold Type:
140+--
141+-- The order of arguments allows 'Category' and 'Arrow' instances but precludes
142+-- contravariant and contra-applicative.
143+--
144+-- = Unfolds and Streams
145+--
146+-- An 'Unfold' type is the same as the direct style 'Stream' type except that
147+-- it uses an inject function to determine the initial state of the stream
148+-- based on an input. A stream is a special case of Unfold when the static
149+-- input is unit or Void.
150+--
151+-- This allows an important optimization to occur in several cases, making the
152+-- 'Unfold' a more efficient abstraction. Consider the 'concatMap' and
153+-- 'unfoldMany' operations, the latter is more efficient. 'concatMap'
154+-- generates a new stream object from each element in the stream by applying
155+-- the supplied function to the element, the stream object includes the "step"
156+-- function as well as the initial "state" of the stream. Since the stream is
157+-- generated dynamically the compiler does not know the step function or the
158+-- state type statically at compile time, therefore, it cannot inline it. On
159+-- the other hand in case of 'unfoldMany' the compiler has visibility into
160+-- the unfold's state generation function, therefore, the compiler knows all
161+-- the types statically and it can inline the inject as well as the step
162+-- functions, generating efficient code. Essentially, the stream is not opaque
163+-- to the consumer in case of unfolds, the consumer knows how to generate the
164+-- stream from a seed using a known "inject" and "step" functions.
165+--
166+-- A Stream is like a data object whereas unfold is like a function. Being
167+-- function like, an Unfold is an instance of 'Category' and 'Arrow' type
168+-- classes.
169+--
170+-- = Unfolds and Folds
171+--
172+-- Streams forcing a closed control flow loop can be categorized under
173+-- two types, unfolds and folds, both of these are duals of each other.
174+--
175+-- Unfold streams are really generators of a sequence of elements, we can also
176+-- call them pull style streams. These are lazy producers of streams. On each
177+-- evaluation the producer generates the next element. A consumer can
178+-- therefore pull elements from the stream whenever it wants to. A stream
179+-- consumer can multiplex pull streams by pulling elements from the chosen
180+-- streams, therefore, pull streams allow merging or multiplexing. On the
181+-- other hand, with this representation we cannot split or demultiplex a
182+-- stream. So really these are stream sources that can be generated from a
183+-- seed and can be merged or zipped into a single stream.
184+--
185+-- The dual of Unfolds are Folds. Folds can also be called as push style
186+-- streams or reducers. These are strict consumers of streams. We keep pushing
187+-- elements to a fold and we can extract the result at any point. A driver can
188+-- choose which fold to push to and can also push the same element to multiple
189+-- folds. Therefore, folds allow splitting or demultiplexing a stream. On the
190+-- other hand, we cannot merge streams using this representation. So really
191+-- these are stream consumers that reduce the stream to a single value, these
192+-- consumers can be composed such that a stream can be split over multiple
193+-- consumers.
194+--
195+-- Performance:
196+--
197+-- Composing a tree or graph of computations with unfolds can be much more
198+-- efficient compared to composing with the Monad instance. The reason is that
199+-- unfolds allow the compiler to statically know the state and optimize it
200+-- using stream fusion whereas it is not possible with the monad bind because
201+-- the state is determined dynamically.
202+--
203+-- Reader:
204+--
205+-- An unfold acts as a reader (see 'Reader' monad). The input to an unfold acts
206+-- as the read-only environment. The environment can be extracted using the
207+-- 'identity' unfold (equivalent to 'ask') and transformed using 'lmap'.
91
208
92------------------------------------------------------------------------------
209------------------------------------------------------------------------------
93-- Monadic Unfolds
210-- Monadic Unfolds
94------------------------------------------------------------------------------
211------------------------------------------------------------------------------
95
212
96−-- The order of arguments allows 'Category' and 'Arrow' instances but precludes
97−-- contravariant and contra-applicative.
98−--
99−-- An unfold is akin to a reader. It is the streaming equivalent of a reader.
100−-- The argument @a@ is the environment of the reader. That's the reason the
101−-- default unfolds in various modules are called "read".
102−--
103-- | An @Unfold m a b@ is a generator of a stream of values of type @b@ from a
213-- | An @Unfold m a b@ is a generator of a stream of values of type @b@ from a
104-- seed of type 'a' in 'Monad' @m@.
214-- seed of type 'a' in 'Monad' @m@.
105--
215--
@@ -130,7 +240,7 @@ mkUnfoldrM step = Unfold step pure
130-- The type 'Step' is isomorphic to 'Maybe'. Ideally unfoldrM should be the
240-- The type 'Step' is isomorphic to 'Maybe'. Ideally unfoldrM should be the
131-- same as mkUnfoldrM, this is for compatibility with traditional Maybe based
241-- same as mkUnfoldrM, this is for compatibility with traditional Maybe based
132-- unfold step functions.
242-- unfold step functions.
133−--
243+
134-- | Build a stream by unfolding a /monadic/ step function starting from a seed.
244-- | Build a stream by unfolding a /monadic/ step function starting from a seed.
135-- The step function returns the next element in the stream and the next seed
245-- The step function returns the next element in the stream and the next seed
136-- value. When it is done it returns 'Nothing' and the stream ends.
246-- value. When it is done it returns 'Nothing' and the stream ends.
@@ -369,6 +479,7 @@ instance Functor m => Functor (Unfold m a) where
369------------------------------------------------------------------------------
479------------------------------------------------------------------------------
370
480
371-- XXX Shouldn't this be Unfold m (m a) a ?
481-- XXX Shouldn't this be Unfold m (m a) a ?
482+
372-- | The unfold discards its input and generates a function stream using the
483-- | The unfold discards its input and generates a function stream using the
373-- supplied monadic action.
484-- supplied monadic action.
374--
485--
@@ -386,7 +497,7 @@ fromEffect m = Unfold step inject
386
497
387-- XXX Shouldn't this be Unfold m a a ? Which is identity. Should this function
498-- XXX Shouldn't this be Unfold m a a ? Which is identity. Should this function
388-- even exist for Unfolds. Should we have applicative/Monad for unfolds?
499-- even exist for Unfolds. Should we have applicative/Monad for unfolds?
389−--
500+
390-- | Discards the unfold input and always returns the argument of 'fromPure'.
501-- | Discards the unfold input and always returns the argument of 'fromPure'.
391--
502--
392-- > fromPure = fromEffect . pure
503-- > fromPure = fromEffect . pure
core/streamly-core.cabal+1
@@ -45,6 +45,7 @@ extra-source-files:
45 src/DocTestDataParser.hs
45 src/DocTestDataParser.hs
46 src/DocTestDataStream.hs
46 src/DocTestDataStream.hs
47 src/DocTestDataStreamK.hs
47 src/DocTestDataStreamK.hs
48+ src/DocTestDataUnfold.hs
48
49
49 -- This is duplicated
50 -- This is duplicated
50 src/Streamly/Internal/Data/Array/ArrayMacros.h
51 src/Streamly/Internal/Data/Array/ArrayMacros.h