
Frerich Raabe wrote:
I also used to share this "Every function in Haskell is pure, as long as it does not use any of the unsafe* functions" view but by now I'm wondering whether that's really a useful definition. It may be true that
putStrLn :: String -> IO ()
is pure in the sense that it only yields a 'recipe' for printing the given string instead of actually printing it. However, I think it's important to realize that putStrLn *could* actually yield a poisoned recipe, something which not *only* prints a string but which also plays a sound at 4AM. And the types won't let you know whether this is the case.
Hence, even though putStrLn may be pure in the classical 'same input yields same output' sense, I wondr whether it's more useful to consider putStrLn to be impure on the grounds that a value of type 'IO a' means "anything can happen, and whatever happens doesn't necessarily only depend on the arguments".
Well, purity of functions is still a useful concept, because it provides a useful invariant in the types. For instance, the well-known function map :: (a -> b) -> [a] -> [b] may assume that the first argument always returns equal results given equal arguments and hence can be applied in any order and as often as desired. On the other hand, mapM :: (a -> IO b) -> [a] -> IO [b] may not assume that and must be careful about the sequence of operations. Of course, an action IO a means that "anything can happen", but I don't think it's useful to call that "impure". It's a good thing that the nastiness of the `IO` type constructor is separated cleanly from the properties of the function arrow `->`. That leaves the question of how to reason about `IO` programs. This is explored in detail in Simon Peyton-Jones' tutorial "Tackling the awkward squad: monadic input/output, concurrency, exceptions, and foreign-language calls in Haskell" http://research.microsoft.com/en-us/um/people/simonpj/papers/marktoberdorf/ You may also like "The Operational Monad Tutorial", which doesn't cover IO, but tries to explain how other monads can be understood and implemented in terms of operational semantics: http://apfelmus.nfshost.com/articles/operational-monad.html Best regards, Heinrich Apfelmus -- http://apfelmus.nfshost.com