It's a trick! Everything in Haskell is pure -- you have to go outside of Haskell (like into the runtime system) to get something impure. (...but this is not a helpful answer until very late in your Haskell experience.)
–
Daniel WagnerMar 3 '13 at 12:43

3 Answers
3

Essentially you want to keep as little code as possible in the "impure section". Code written in the IO monad is forever tainted with insecurity. A function with the signature IO Int will return an integer in the IO monad, but it could on top of that send nuclear missiles to the moon. We have no way of knowing without studying every line of the code.

For example, let's say you want to write a program that takes a string and appends ", dude" to it.

main = do
line <- getLine
putStrLn $ line ++ ", dude"

Some of the parts of the code are required to be in the IO monad, because they have side effects. This includes getLine and putStrLn. However, putting the two strings together does not.

The signature of addDude shows that it is pure: String -> String. No IO here. This means we can assume that addDude will behave at least in that way. It will take one string and return one string. It is impossible for it to have side effects. It is impossible for it to blow up the moon.

Nice answer. Apologies for taking the liberty to fix a typo in the code. I'd also suggest that the signature of addDude would be better at showing purity if it were present in the code. One reason for writing explicit type signatures is exactly to document and verify what bad stuff definitely isn't going to happen.
–
pigworkerMar 3 '13 at 11:31

@pigworker, thanks! You know, I thought about putting it in there, wasn't sure it would matter so I went for conciceness.
–
Erik KronbergMar 3 '13 at 14:11

1

+1 for eloquent discussion of the isuue. Yet, wouldn't be the moon a better place for all those missiles? At least we could be quite sure nobody gets killed or poisoned if we let them go there ....
–
IngoMar 3 '13 at 21:27

Separating pure from impure functions means that you can know more about what your code is going to do. For example, when you say 1 + 2, you know for sure by its type (Int -> Int -> Int) that the only thing it does is take two numbers and produce a third number. If its type were Int -> Int -> IO Int, it might move a robot arm each time it adds the two numbers.

Everything in Haskell is pure. What you are reading about is likely about code inside the IO mondad vs. outside. Once you put something into the IO monad, it can never "escape" -- you have to stay in the IO monad. Therefore, the IO monad has a tendency to "invade" your code -- if you have a thing that returns IO, then any code that calls that also has to return IO, and so on. Therefore it is best to use the IO monad only where it is necessary, at as top level of the program as possible, and separate out any parts of the computation that are pure into pure functions.