m is a construction to encapsulate computation. You can think of a monad as a box with a function in it. Binding monad
a to monad
b is putting box B in box A. That way, you ensure function A is executed before function B: B cannot be executed before because it needs the result of A. This way it's possible to control evaluation order in a lazy programming language1.
In the case of the IO Monad the purpose is indeed to interconnect the program itself (which is purely functional) with the outside world (which is impure). This is not the same as connecting software and hardware. The program still runs on hardware (the processor). However, with the IO Monad a pure function may have side effects (for example, writing to a file). Monads itself are just constructions and may be used for anything, even simple arithmetic. So, the comparison with a human can only be made with the IO Monad.
What is important that with the IO Monad you somehow detach side effects from a pure function so that it remains pure. Does that look like a human? Well...
If you think
- there is a clear distinction between mind and body
- the mind is purely mathematical
- a human is defined as that which allows the mind to remain purely mathematical while connecting to a body
then yes, you are kind of like the IO Monad. But, there are valid reasons for not agreeing with any of the three points above:
- Arguments against dualism
- What about emotions?
- Surely a human is more than this? Does a human not also exist of his mind and body themselves?
A better analogy
If I were to simulate humans in a functional programming language (and indeed I did this, simulating a soccer team in Clean some months ago), I would consider a human to be a function which takes a world and yields a new world: a human has senses with which he observes the world, processes them, and somehow changes the world by acting. Thus, we could write the type of a human as
Human :: World -> World.
Now, it's important that we cannot write a function which applies the actions of two humans like
two_humans :: Human Human World -> (World, World)
two_humans h1 h2 world = (h1 world, h2 world)
After applying this function we have two worlds, which can never be the case. The pure and lazy functional programming language Clean uses uniqueness typing to avoid this problem. What you do is you say that
World is unique, so that only one function can use it a time. That way, only one
World will ever exist in the program.
1: What is controlling evaluation order?
In a lazy programming language, functions are executed when the result is needed, rather than when the processor reaches the point the function is written. Suppose there were a simple function
output :: String -> Void which outputs the input string to the screen and yields nothing, one could write a function
print = (output "Hello ", output "world!")
When executed, this may show both
Hello world! and
, because the order in which the functions are executed is undefined.
output function could look like
output :: String -> (*World -> (Void, *World)). Here,
*World is the unique outside world.
output takes a string and yields a function from
*World to nothing and a new
*World: the function changes the world. The
print function would be written as
print = output "world!" (snd (output "Hello " world))
snd yields the second element of a tuple. Because the leftmost
output needs the
*World that is yielded by the rightmost
output, it cannot be executed before the rightmost
output. Therefore, the program always outputs
Note, that this syntax is confusing (it's right to left) and a lot of typing. Haskell has the bind function (
>>=) to easily bind two monads together.