4 ms·
I feel that one of the biggest misconceptions about monads and IO in Haskell is that they are an "escape hatch" in the language that allows you to perform imper
by wz1000 10y ago
I feel that one of the biggest misconceptions about monads and IO in Haskell is that they are an "escape hatch" in the language that allows you to perform imperative actions. This is plainly false. Monads are just another functional programming idiom, defined by two regular functions, `return` and `(>>=)`.
What monads allow you to do is have a purely functional model to represent IO, among a great many other things. Haskell is, in a sense, the best imperative programming language ever created, because it lets you manipulate imperative statements in a purely functional manner. You can stick statements in data structures, compose them, replicate them, generate them and only evaluate them when you want to.
- js8 10y agoI agree. But this is a misconception about functional programming in general, that its purpose is to somehow replace imperative actions that are done by the computer system with something else which is not imperative. But that's not the goal. Functional programming is there to provide a better formalism for writing programs, it doesn't want to change the way the computers actually execute the programs (or how the systems eventually internally work). That means more work for the compilers to figure out how to make the same old imperative program out of a functional one, which is a good thing (it's generally the direction the compilers evolve). Benefits of functional programming are not in how programs are executed (quite to the contrary - it's actually more effort to make them as efficient as good imperative programs), but in how the programs are written by people. I think the article is a little confused about this. For another example to see this, even notion of non-pure function goes already in this direction. Today, having lots of (small) functions seems to have negligible downsides, but historically this wasn't the case at all, look at any better program that had to fit into memory of an 8-bit computer. These were rarely written in this style, because compilers were simply not capable enough to produce a reasonably compact spaghetti machine code out of those (by means of inlining, for instance).
- wott 10y agoTo sum up: harder to write, harder to compile, harder to make efficient. Hum... difficult to qualify it as 'better' after this.
- js8 10y agoI agree with you. Yet, strangely enough, it is better. Maybe we could say, easier to read, easier to modify, easier to reuse? Let me return to that last example. Take a program written in procedural style, and an identical program written in a big ball of mud style (all variables are global, one big control flow). This is a discussion from like 1960s. It's harder to write for human, and harder for compiler to compile and make efficient program in procedural style. Yet, I am sure today, you would prefer procedural style. It makes sense (trust me, I actually work with big-ball-of-mud programs written 30+ years ago at work, AMA). I don't care what work the compiler has to do, I care about my own time. Functional programming is just another step on that road. As a side note, I really think people who prefer FP should avoid (over)selling it as more computationally efficient approach, because it still isn't (even though it probably will be in the future). It's a little bit of optimistic dishonesty that IMHO hurts adoption of FP and feeds the misconception that I talk about.
- marcosdumay 10y agoHarder to make errors, easier to modify. But what you said is true too.
- ridiculous_fish 10y agoMonad is not itself an escape hatch, but Haskell's escape hatches are mostly monads (ST, IO, etc). Monads may be a functional programming idiom, but monads in Haskell are deeply magical. So "monad = escape hatch" has some basis in reality. It's important to distinguish between imperative code and IO. Many pure algorithms are most naturally expressed imperatively. Viewed in this way, Haskell is actually pretty bad at imperative programming. Myers Diff is an example. See diffST2 at https://hackage.haskell.org/package/uni-util-2.3.0.1/docs/src/Util-Myers.html https://hackage.haskell.org/package/uni-util-2.3.0.1/docs/sr... for the Haskell version. Notice how simple expressions in Myers's paper, such as `V[k−1] < V[k+1]`, explode into ugly things: vkplus <- readArray v (k+1) vkminus <- readArray v (k-1) (x,l0) <- if vkminus < vkplus... Here we've paid a syntax tax for mixing the "imperative" array-read with the "pure" value comparison. Similarly, notice how the 10-line recursive `scan` is a less-readable implementation of a one-line while loop in the Myers paper. So in practice, Haskell is rather painful to use as an imperative programming language.
- Mathnerd314 10y agoTechnically the escape hatches are only the stuff here: https://hackage.haskell.org/package/ghc-prim-0.5.0.0/docs/GHC-Prim.html https://hackage.haskell.org/package/ghc-prim-0.5.0.0/docs/GH... So you could write case readIntArray# v (k +# 1#) realWorld# of (# vkp, _ #) -> case readIntArray# v (k -# 1#) realWorld# of (# vkm, _ #) -> case vkp <# vkm of 0# -> ... 1# -> ... with syntax sugar reasonably close to V ! (k+1) < V ! (k-1). The problem is the state tokens; I ignored them by using realWorld# and _ above, but that makes the code not referentially transparent. So in practice, Haskell always passes them around in a monad (Except in all the core libraries, which use things like accursedUnutterablePerformIO to go back down to the thunk level: https://github.com/haskell/bytestring/blob/master/Data/ByteString/Internal.hs#L527 https://github.com/haskell/bytestring/blob/master/Data/ByteS...). But reads are (mostly) pure so it shouldn't break anything to provide a pure interface. Alternatively, the verbosity can be seen as a syntax problem, with the corresponding solution of a better do-notation: https://www.reddit.com/r/haskell/comments/4dsb2b/thoughts_on_an_inlinedobind_extension/ https://www.reddit.com/r/haskell/comments/4dsb2b/thoughts_on... so you'd get something like (x,l0) <- if (<- v ! (k-1)) < (<- v ! (k+1)) ... (again using ! for readArray, which has some impracticalities) That's still not quite as good as C, it really needs the notion of sequence points: https://en.wikipedia.org/wiki/Sequence_point https://en.wikipedia.org/wiki/Sequence_point
- Silhouette 10y agoMonads are just another functional programming idiom, defined by two regular functions, `return` and `(>>=)`. But in terms of I/O with the outside world, monadic patterns become useful in Haskell because the type of your main function is also `IO ()`. That's the "escape hatch", not the use of monads in itself.
- KirinDave 10y agoEveryone knows the real escape hatch is unsafePerformIO!