Hi,
I’ve never written a monad tutorial, but I’ve done the next best thing, which is writing a Haskell streaming library. It’s called jet-stream and it looks like this:
ghci> File "foo.txt" & J.jet @Line & J.limit 10 & J.sink stdout
The initial motivation was not within Haskell, it was working with Java Streams. The Java Stream
type has the interesting feature that flatMap
is also an implicit bracket
: if the Stream
created within the callback allocates some resource, the resource it’s freed once flapMap
exits. Furthermore, it plays well with methods like limit
: if we limit
the result of a flatMap
, the finalizer is not lost, and it’s called when we exhaust the result of the limit
. I wondered how something like that would work in Haskell.
jet-stream uses a tiny amount of linear types to ensure that the bracket-like control operations we might want to lift are not too weird. Therefore, the library is GHC >= 9 only.
Another motivation is that I wanted a very simple streaming type with only one type parameter: the type of yielded elements. Also, its Monad
and Monoid
instances should be analogous to those of normal lists. This has required some compromises: the effects are always in IO
(no monad transformers in sight) and sometimes exceptions are required to notify of errors.
There aren’t a lot of grouping operations, either, and they aren’t as elegant as they are for example in streaming. That said, you can interface with the foldl library for performing grouping as a “terminal step”.
I do provide some basic concurrency and external process invocation functionality though.