4 ms·
Monad 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 H
by ridiculous_fish 10y ago
Monad 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