Could anyone give some pointers on why the impure computations in Haskell are modelled as monads?
I mean monad is just an interface with 4 operations, so what was the reasoning to modelling side-effects in it?
Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.
Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.
Lost your password? Please enter your email address. You will receive a link and will create a new password via email.
Please briefly explain why you feel this question should be reported.
Please briefly explain why you feel this answer should be reported.
Please briefly explain why you feel this user should be reported.
Suppose a function has side effects. If we take all the effects it produces as the input and output parameters, then the function is pure to the outside world.
So, for an impure function
we add the RealWorld to the consideration
then
fis pure again. We define a parametrized data typetype IO a = RealWorld -> (a, RealWorld), so we don’t need to type RealWorld so many times, and can just writeTo the programmer, handling a RealWorld directly is too dangerous—in particular, if a programmer gets their hands on a value of type RealWorld, they might try to copy it, which is basically impossible. (Think of trying to copy the entire filesystem, for example. Where would you put it?) Therefore, our definition of IO encapsulates the states of the whole world as well.
Composition of "impure" functions
These impure functions are useless if we can’t chain them together. Consider
We want to
How would we do it if we could access the real world states?
We see a pattern here. The functions are called like this:
So we could define an operator
~~~to bind them:then we could simply write
without touching the real world.
"Impurification"
Now suppose we want to make the file content uppercase as well. Uppercasing is a pure function
But to make it into the real world, it has to return an
IO String. It is easy to lift such a function:This can be generalized:
so that
impureUpperCase = impurify . upperCase, and we can write(Note: Normally we write
getLine ~~~ getContents ~~~ (putStrLn . upperCase))We were working with monads all along
Now let’s see what we’ve done:
(~~~) :: IO b -> (b -> IO c) -> IO cwhich chains two impure functions togetherimpurify :: a -> IO awhich converts a pure value to impure.Now we make the identification
(>>=) = (~~~)andreturn = impurify, and see? We’ve got a monad.Technical note
To ensure it’s really a monad, there’s still a few axioms which need to be checked too:
return a >>= f = f af >>= return = ff >>= (\x -> g x >>= h) = (f >>= g) >>= hLeft as exercise.