In a lazy, pure language like Haskell, there's the problem that since a print function doesn't actually compute anything, it doesn't return anything that makes sense functionally; it's not a function in the mathematical sense. In Haskell, a function is only evaluated when it needs to be (i.e. potentially out of order), and functions called with the same arguments can be memoized, and functions that don't return anything can conceptually be eliminated entirely. So the challenge is to somehow tag the print function as being unmemoizable.
To do this, as far as I recall (it's been a while), the GHC's implementation of IO says that the monad wraps a value of a type "RealWorld". Every time you bind/return an IO function, you are sending the current RealWorld and then getting a new RealWorld back. This is hidden from the caller since it's a detail of the monad that you don't need to see. As far as I know, the world value is just a dummy value that is optimized away and doesn't exist at run time. But by forcing every IO to depend on the previous result, the "computations" will be chained in the right order.
Edit: Haskell wiki has more: https://wiki.haskell.org/IO_inside
getLine :: RealWorld -> (String, RealWorld)
putLine :: RealWorld -> String -> RealWorld
And some code like:
Let (line, w1) = getLine w0
w2 = putLine w1 line
w3 = putLine w2 "other stuff"
w4 = putLine w3 line
...
Now, imagine an optimization compiler for some reason decides it would be better to recompute `line`, rather than hang on to the value in the interim. It would be well within its rights to do so, because referential transparency guarantees that this is safe.IIRC ghc essentially "plays dumb" and just never duplicates a computation (which is not typically a desirable optimization at this level, though register allocators will sometimes do it). But it's arguably a hack.
A better metaphor is to think of values of type IO a as fragments of a script in some other (imperative) language. The Haskell program merely computes the script, and the runtime then takes care of actually executing it. In this sense, effects in Haskell are not "side" -- they are first class citizens. What order the fragments of the imperative program are computed in (or how many times) is independent of the text of the final program.
In very early versions of Haskell, main had a type roughly like [Response] -> [Request]; you computed a list of things for the runtime to do, as a function of the results of its (hopefully) previous commands. This kinda works, but it's easy to deadlock by creating a circular data dependency. What the Monad structure does for you is avoid that problem, by making it impossible to depend on a future value.
It's also worth pointing out that all of this is specific to IO; understanding monads in general are neither necessary nor sufficient to understand Haskell's IO.
I want to make sure that I'm understanding this bit correctly:
>A better metaphor is to think of values of type IO a as fragments of a script in some other (imperative) language. The Haskell program merely computes the script, and the runtime then takes care of actually executing it. In this sense, effects in Haskell are not "side" -- they are first class citizens. What order the fragments of the imperative program are computed in (or how many times) is independent of the text of the final program.
In Wadler's paper, the monadic output example looks like this:
type M a = (Output, a)
type Output = String
unit :: a → M a
unit a = (“ ”, a)
(*) :: M a → (a → M b) → M b
m * k = let(x, a) = m in
let(y, b) = k a in
(x ++ y, b)
out :: Output → M ()
out x = (x, ())
where each function, instead of returning a simple numeric value, returns a tuple of a string (the output to be printed) and a number (the value to be returned). If you wrote this function out in Haskell, you would have access the output text in the form of a lazy list of strings.If we can think of IO values as fragments of an imperative script that are handled at runtime, then that makes me think that the Haskell compiler doesn't use the strategy presented in Wadler's paper (in the case of printing output, returning a lazy list of strings to be printed), and instead just performs the specified side effects directly, knowing that semantics of the IO monad guarantee that things will be sequenced correctly. Do I have this right?
The code you sketch out above is basically the Writer Monad, which exists in the libraries, and does see use, but it's not IO -- as I mentioned above the semantics of IO don't entirely just fall out of the monadic structure.
But I find the computed-imperative-program description lends itself to thinking about IO values as values in a way that thinking about them as type system goop to tame side effects doesn't; for example, the program:
import Data.List (intersperse)
import Control.Concurrent (threadDelay)
main = sequence_ $ intersperse (threadDelay 1000000) (map print [1..])
will print out the natural numbers, one per second until you kill it. It works by constructing a (lazily evaluated) list of actions to perform, which alternately print out a number or wait for one second. sequence_ has type [IO a] -> IO (), and it just performs each action in the list in sequence (its type is actually a bit more general than this, but..).This kind of code is really weird to think about from the "tamed side-effects" model, but very natural from the "computing a script" model.
putStr :: String -> IO ()
Here, () is the unit type, which is similar to null/nil in other languages. In other words, I/O functions like putStr etc. don't return anything. putStr internally calls lower-level functions that actually write to a file descriptor.Some people get into Haskell thinking that functions can't have side effects because Haskell is "pure", but that's not right. Rather, as the parent commenter say, they can have all the side effects they want, and the consistency and purity of the program's execution is preserved through the use of monads.
Haskell is considered a pure functional language where everything is immutable, but that's not true, either. A lot of the GHC standard library uses mutation (e.g. with IORefs) for performance reasons. For example, putStr ends up writing to an internal byte buffer that is modified directly.
Not really.
A monad:
1) helps translate values from one domain to another.
2) helps handle the logic in a series of operations.
One use of that is to enrich data with the possibility of carrying some other information (e.g. the Optional/Maybe that can carry an error). But that's not essential to what a monad does, and monads can be used for all kinds of things.
The description of a monad as a "programmable semicolon" captures that a little better. Semicolons in that phrase are meant to refer to the semicolons in C or Java, that separate different expressions.
So, in a program like:
do this; do that; do another thing; ...
Monads helps pass values between the various steps, and help determine what happens with the sequence of operations (the program wont have actual semicolons between steps in Haskell e.g. -- it's just how we notate a number of expression in C-like style for example's sake).
So my question is this: in languages which use monads (like Haskell), is this how monads are actually implemented? Does, say, printing values in Haskell actually involve keeping track of a lazy stream of output text, or does GHC just print out values the way an imperative language would, and use the concept of monads as a way to satisfy the type-system requirements?