A real implementation performs the I/O as the associated monad is evaluated, and relies on lazy evaluation to only evaluate the monad that is returned
Monads are the I/O mechanism of #Haskell . Monads can be thought of as wrapping up an
object so that it may only be accessed in a restricted manner. Once a value has been placed in a monad,
it cannot be extracted. Monads can be sequenced together, with the value from the first monad passed
into the second. The resulting monad cannot then be split up. This allows values held in monads to be
passed around and used in a controlled fashion, but the values may never “escape” from the monad.
I/O is achieved by creating a monad that performs the program by sequencing together input and
output functions. The runtime system then performs the sequenced parts of the monad, evaluating the
contained closures as necessary. The monad is effectively a “list of things to do” returned by the program
and evaluated by the runtime, except that since the list contains closures the exact operations performed
can be data dependent.2 The evaluation of I/O outside the program body allows the state information to
be held externally to the function (preventing the need for linear state objects)
Synchronous Streams An alternative to creating a function that processes a stream of values by iterating over the elements is to make all the I/O values on a stream of data into a single value that is
manipulated in its entirety. This is the approach used in languages such as Lucid [8] and Lustre [60].
The stream is the primitive datatype, and basic arithmetic and logic functions are treated as mapping
functions over the entire streams.
A real implementation performs the I/O as the associated monad is evaluated, and relies on lazy evaluation to only evaluate the monad that is returned
@brokenix Eh... no. You can do arbitrary IO without ever touching monads or something else beyond lambdas.