on master help sign in
update README (exceptions), add doc on transformers
5cbcd5bHarendra Kumar
README.md+72−39
@@ -11,46 +11,57 @@
11## Streaming Concurrently
11## Streaming Concurrently
12
12
13Haskell lists express pure computations using composable stream operations like
13Haskell lists express pure computations using composable stream operations like
14−`:`, `unfold`, `map`, `filter`, `zip` and `fold`. Streamly extends this data
14+`:`, `unfold`, `map`, `filter`, `zip` and `fold`. Streamly is exactly like
15−flow programming model of pure lists to lists of concurrent monadic
15+lists except that it can express sequences of pure as well as monadic
16−computations (streams) using the same primitives.
16+computations aka streams. More importantly, it can express monadic sequences
17−
17+with concurrent execution semantics without introducing any additional APIs.
18+
18−Streamly expresses concurrency using the list primitives, and standard, well
19+Streamly expresses concurrency using standard, well known abstractions.
19−known abstractions, without having to know any low level notions of concurrency
20+Concurrency semantics are defined for list operations, semigroup, applicative
21+and monadic compositions. Programmer does not need to know any low level
20−like threads, locking or synchronization. Concurrency is automatically scaled
22+notions of concurrency like threads, locking or synchronization. Concurrent
23+and non-concurrent programs are fundamentally the same. A chosen segment of
24+the program can be made concurrent by annotating it with an appropriate
25+combinator. We can choose a combinator for lookahead style or asynchronous
26+concurrency. Concurrency is automatically scaled up or down based on the
21−up or down based on the need of the application, so that we can say goodbye to
27+demand from the consumer application, we can finally say goodbye to managing
22−managing thread pools and associated sizing issues as well. This is true,
28+thread pools and associated sizing issues. The result is truly fearless
23−fearless and declarative concurrency. Streamly can be thought of as concurrent
29+and declarative monadic concurrency.
24−monadic lists, if you know Haskell lists then you already know how to use
25−streamly.
26
30
27## Where to use streamly?
31## Where to use streamly?
28
32
33+Streamly is a general purpose programming framwework. It can be used equally
34+efficiently from a simple `Hello World!` program to a massively concurrent
29−Everywhere. The answer to this question would be similar to the answer to -
35+application. The answer to the question, "where to use streamly?" - would be
36+similar to the answer to - "Where to use Haskell lists or the IO monad?".
30−"Where do I use Haskell lists?". Streamly generalizes lists to monadic
37+Streamly generalizes lists to monadic streams, and the `IO` monad to
31−streams, and IO monad to non-deterministic stream composition with concurrency. The
38+non-deterministic and concurrent stream composition. The `IO` monad is a
32−`IO` monad becomes a special case of streamly, if we use single element streams
39+special case of streamly; if we use single element streams the behavior of
33−the behavior of streamly is identical to the IO monad. It can be replaced with
40+streamly becomes identical to the IO monad. The IO monad code can be replaced
34−streamly by just prefixing IO actions with `liftIO`, without any loss of
41+with streamly by just prefixing the IO actions with `liftIO`, without any other
35−performance. Pure lists too become a special case of streamly; if we use the
42+changes, and without any loss of performance. Pure lists too are a special
43+case of streamly; if we use `Identity` as the underlying monad, streamly
36−`Identity` monad, streams turn into pure lists. Non-concurrent programs become
44+streams turn into pure lists. Non-concurrent programs are just a special case
37−a special case of concurrent ones, by just adding a combinator, a non-concurrent
45+of concurrent ones, simply adding a combinator turns a non-concurrent program
38−program becomes concurrent.
46+into a concurrent one.
39−
47+
40−We can say that streamly is a superset of lists and IO, with builtin
48+In other words, streamly combines the functionality of lists and IO, with
41−concurrency. If you want to write a program that involves IO, concurrent or
49+builtin concurrency. If you want to write a program that involves IO,
42−not, then you can just use streamly as the base monad, heck, you could even use
50+concurrent or not, then you can just use streamly as the base monad, in fact,
43−streamly for pure computations, as streamly performs at par with pure lists or
51+you could even use streamly for pure computations, as streamly performs at par
44−`vector`. In fact, streamly is better than lists because it appends much
52+with pure lists or `vector`.
45−faster than lists, you do not need difference lists for that.
53+
46−
54+## Why data flow programming?
55+
47−If you need convincing for using streaming or data flow programming paradigm
56+If you need some convincing for using streaming or data flow programming
48−itself then try to answer this question - why do we use lists? It boils down to
57+paradigm itself then try to answer this question - why do we use lists in
49−why we use functional programming in the first place, and Haskell is successful
58+Haskell? It boils down to why we use functional programming in the first place.
59+Haskell is successful in enforcing the functional data flow paradigm for pure
50−in enforcing this for pure computations, but not for monadic computations. In
60+computations using lists, but not for monadic computations. In the absence of a
51−the absence of a standard, easy to use or enforced data flow programming
61+standard and easy to use data flow programming paradigm for monadic
52−library for monadic computations, and the IO monad providing an escape hatch to
62+computations, and the IO monad providing an escape hatch to an imperative
53−an imperative model, we just love to fall into the imperative trap.
63+model, we just love to fall into the imperative trap, and start asking the same
64+fundamental question again - why do we have to use the streaming data model?
54
65
55## Show me an example
66## Show me an example
56
67
@@ -89,9 +100,9 @@ main = runStream $ aheadly $ listDirRecursive
89```
100```
90
101
91Isn't that magical? What's going on here? Streamly does not introduce any new
102Isn't that magical? What's going on here? Streamly does not introduce any new
92−abstractions, it just uses the standard abstractions like `Semigroup` or
103+abstractions, it just uses standard abstractions like `Semigroup` or
93`Monoid` to combine monadic streams concurrently, the way lists combine a
104`Monoid` to combine monadic streams concurrently, the way lists combine a
94−sequence of pure values non-concurrently. Therefore, the `foldMap` in the code
105+sequence of pure values non-concurrently. The `foldMap` in the code
95above turns into a concurrent monoidal composition of a stream of `readdir`
106above turns into a concurrent monoidal composition of a stream of `readdir`
96computations.
107computations.
97
108
@@ -348,6 +359,22 @@ rate. Rate control works precisely even at throughputs as high as millions of
348yields per second. For more sophisticated rate control see the haddock
359yields per second. For more sophisticated rate control see the haddock
349documentation.
360documentation.
350
361
362+## Exceptions
363+
364+From a library user point of view, there is nothing much to learn or talk about
365+exceptions. Synchronous exceptions work just the way they are supposed to work
366+in any standard non-concurrent code. When concurrent streams are combined
367+together, exceptions from the constituent streams are propagated to the
368+consumer stream. When an exception occurs in any of the constituent streams
369+other concurrent streams are promptly terminated. Exceptions can be thrown
370+using the `MonadThrow` instance.
371+
372+There is no notion of explicit threads in streamly, therefore, no
373+asynchronous exceptions to deal with. You can just ignore the zillions of
374+blogs, talks, caveats about async exceptions. Async exceptions just don't
375+exist. Please don't use things like `myThreadId` and `throwTo` just for fun!
376+
377+
351## Reactive Programming (FRP)
378## Reactive Programming (FRP)
352
379
353Streamly is a foundation for first class reactive programming as well by virtue
380Streamly is a foundation for first class reactive programming as well by virtue
@@ -419,6 +446,12 @@ For more information, see:
419 * [Quick tutorial comparing streamly with the async package](https://github.com/composewell/streamly/blob/master/docs/Async.md)
446 * [Quick tutorial comparing streamly with the async package](https://github.com/composewell/streamly/blob/master/docs/Async.md)
420 * [Concurrency benchmarks comparing streamly with async](https://github.com/composewell/concurrency-benchmarks)
447 * [Concurrency benchmarks comparing streamly with async](https://github.com/composewell/concurrency-benchmarks)
421
448
449+## Support
450+
451+If you require professional support, consulting, training or timely
452+enhancements to the library please contact
453+[support@composewell.com](mailto:support@composewell.com).
454+
422## Contributing
455## Contributing
423
456
424The code is available under BSD-3 license
457The code is available under BSD-3 license
docs/Async.md → docs/streamly-vs-async.mdrenamed

The content is the same.

docs/transformers.mdnew file+32
@@ -0,0 +1,32 @@
1+## Using Monad Transformers
2+
3+Common monad transformers can be used with streamly serial streams, without any
4+issues. `ReaderT` can be used with concurrent streams as well without any
5+issues.
6+
7+The semantics of monads other than `ReaderT` with concurrent streams are
8+not yet finalized and will change in future, therefore as of now they are not
9+recommended to be used.
10+
11+## Ordering of Monad Transformers
12+
13+In most cases it is a good idea to keep streamly as the top level monad.
14+
15+## State Sharing
16+### Serial Applications
17+
18+Read only global state can always be shared using the `Reader` monad.
19+Read-write global state can be shared either using an `IORef` in the `Reader`
20+monad or using the `State` monad.
21+
22+See `AcidRain.hs` example for a usage of `StateT` in the serially executing
23+portion of the program.
24+
25+### Concurrent Applications
26+
27+The current recommended method for sharing modifiable global state across
28+concurrent tasks is to put the shared state inside an `IORef` in a `Reader`
29+monad or just share the `IORef` by passing it to the required functions. The
30+`IORef` can be updated atomically using `atomicModifyIORef`.
31+
32+The `CirclingSquare.hs` example shares an `IORef` across parallel tasks.
streamly.cabal+9−4
@@ -55,9 +55,13 @@ description:
55 .
55 .
56 Where to find more information:
56 Where to find more information:
57 .
57 .
58− * @README@ shipped with the package for a quick overview
58+ * /Quick Overview/: <src/README.md README file> in the package
59− * "Streamly.Tutorial" module in the haddock documentation for a detailed introduction
59+ * /Detailed Tutorial/: "Streamly.Tutorial" module in the haddock documentation
60+ * /Reference Documentation/: Haddock documentation for the respective modules
61+ * /Examples/: <src/examples examples directory> in the package
60− * @examples@ directory in the package for some simple practical examples
62+ * /Guides/: <src/docs docs directory> in the package, for documentation on
63+ advanced topics, limitations, semantics of the library or on specific use
64+ cases.
61
65
62homepage: https://github.com/composewell/streamly
66homepage: https://github.com/composewell/streamly
63bug-reports: https://github.com/composewell/streamly/issues
67bug-reports: https://github.com/composewell/streamly/issues
@@ -75,7 +79,8 @@ cabal-version: >= 1.10
75extra-source-files:
79extra-source-files:
76 Changelog.md
80 Changelog.md
77 README.md
81 README.md
78− docs/Async.md
82+ docs/streamly-vs-async.md
83+ docs/transformers.md
79 bench.sh
84 bench.sh
80 stack-7.10.yaml
85 stack-7.10.yaml
81 stack-8.0.yaml
86 stack-8.0.yaml