3 ms·
The answer to the posters question is yes... monads are a waste of time if you're using them to handle state changes. It's best to just use explicit threading i
by tathougies 9y ago
The answer to the posters question is yes... monads are a waste of time if you're using them to handle state changes. It's best to just use explicit threading in that case.
The only time (I think) it's okay to use stateful monads in haskell is when it simplifies the code syntactically by removing extra cruft. Otherwise, explicit state is always going to be clearer to understand.
On the other hand, most uses of monads in Haskell are not to handle state. In my Haskell SQL library Beam[1] for example, we use monads to build a relational algebra AST at run-time and then dynamically optimize it. The SQL generating system inspects branches of the AST at run-time to generate sensible SQL expressions. Because the DSL is implemented as a monad, we get a bunch of stuff for free. At my work for example, we use a straightforward haskell `forM` to generate large joins.
Because of the Haskell purity, we can know for sure that re-executing parts of the AST will not be dispruptive, because the code is pure.
I'm currently working on a little utility library for editing rich text with Haskell and I've used the continuation monad to automatically derive a zipper for my data structure. I get O(1) updates at my current position, for free. All I have to do is write a little interpreter. Because of Haskell's purity, I get a lot of functionality without doing anything. This is actually a big deal, as the same implementation in an imperative language involves complicated data structures and O(log n) complexity (look at the GTK text btree source file [2] for the kind of complexity I'm talking about). Because of the flexibility involved with the underlying monad, I have a 'fast' implementation of my zipper for simply modifying text, a 'visual' implementation that records a list of DOM updates to visualize the text as its being edited, and a 'network' implementation that outputs a list of commands for suitable editing. One simple data structure, one monad, three interpreters, and I have a collaborative text editing system.
Ultimately, the point is that you should only use an abstraction if it simplifies your code or reduces the error surface. If it does neither, then it's wasteful
[1] https://github.com/tathougies/beam https://github.com/tathougies/beam
[2] https://github.com/GNOME/gtk/blob/master/gtk/gtktextbtree.c https://github.com/GNOME/gtk/blob/master/gtk/gtktextbtree.c
- kmelva 9y ago> I'm currently working on a little utility library for editing rich text with Haskell and I've used the continuation monad to automatically derive a zipper for my data structure. Could you go into more detail about this?
- tathougies 9y agoSure... most people familiar with zippers know that it can be thought of as the algebraic derivative the underlying type. What’s perhaps less known is that this is the same as ‘differentiating’ the traversal of the data type. The continuation monad is a sort of ‘derivative’ of a computation in that it nearly captures the ‘infinitesmal’ difference between two steps in a computation. If your computation is the traversal of your tree, list, or text markup, then you can make a zipper from that without having to declare new data structures. This is isomorphic to declaring your own data structure. Its only advantage is convenience (that I know of at least). Oleg Kiselyov goes into great detail with this idea and has lots of example code: http://okmij.org/ftp/continuations/zipper.html http://okmij.org/ftp/continuations/zipper.html
- kmelva 9y agoThanks for the answer, it'll keep me busy for a week or two!