The fact that you can write procedures, which produce side-effects, in Haskell, which is supposed to be a pure language, can be confusing.
I think the key to clearing up the confusion is to understand that most Haskell programs are actually programs that produce programs — like preprocessors in CPP. Conal Elliott’s post The C language is purely functional explores this idea.
The Haskell language itself is pure. When evaluated, Haskell expressions have no side effects, and are referentially transparent.
But the value returned by
main in many Haskell programs is an
IO something — which is a procedure that can be executed and may have side effects.
If the GHC didn’t have the built-in ability to take an
IO something and compile it into an executable procedure, then a Haskell program could evaluate expressions all day long, but the resulting values would just disappear into the ether because the program could never output the results to STDOUT, because that is a side-effect.
Haskell has advantages over impure languages not because it removes the ability to write impure procedures, but because it adds the ability to write pure functions, guaranteed to have no side effects and to be referentially transparent. The majority of many programs can and should be written with pure functions, which are easier to maintain, understand, and debug. Often you only need impure procedures for a small part of the program, perhaps only the parts that actually writes output to STDOUT or a database.
Unfortunately, when you need to write impure-procedures in Haskell, there is a great deal of syntactic overhead that I don’t think has to be necessary.
The benefits of Haskell’s IO to me are are:
- I can write pure functions.
- I can also write procedures.
- I can treat procedures as values.
- I clearly see in my code when I am defining a procedure and when I am defining a pure function.
- I clearly see in my code when a procedure is executed.
I’d like to see a language with those benefits, but with additional benefits:
- I can write procedures without the syntactic overhead of the IO Monad required in Haskell.
- I can contain procedures to only operate on specific objects, so that I can limit their effects to a sandbox.
I think such a language is possible. Anyone want to help me create it it?