In Haskell, input-output is a bit of a bother. This is actually quite strange, given that the whole point of a program is to do input-output, and even more-strange given that the most-versatile language for handling input-output is Haskell.
What Haskell does is to strictly compartmentalise input-output. Most-importantly, it is like the Beit Shammai pharisees, who said that if you break one law, you have broken all the Law. (Hint: the Haskell people are correct, which means Shammai was correct, and indeed the Hillelite sages have said that when Shammai is considered to be correct, then we are living in the days of the Messiah—as indeed we are.) So in Haskell, either a function is pure all the way, or it is impure all the way.
What we try to do, in our pharisaical programming mode, is to limit all the sin to one well-defined point, a scapegoat of sorts: when the program starts, in the
main function. So my programs in Haskell really over-exploit command line arguments and environment variables. (In fact, I use environment variables far more than I use command line arguments.) The point is that, in the
main function, we can commit all our input-output, and then let the rest of the program live a pure existence.
But the problem is that, since programs are meant to deal with input-output, every single function is going to require something that came from outside the function—something that came in by input-output. So the
main function, which is our sacrificial lamb, upon whom we heap all our sins, is left to die, having been laid aside by the Haskell system “from the foundation of the World” through no fault of its own, and we who fondle the results of input-output are made the purity of Haskell itself. Haskell made the function that had no sin—the function that is the only-begotten Son of Haskell, the
main function, which has “obtained a name that is above all the other functions“, born of the pure Haskell system itself—to be Sin itself, to be the alpha and omega of input-output, that the rest of our functions that we write might be the purity of Haskell.
main function—both purely a function and purely an IO action at the same time—grew up before him like a hello world, and like a line of code in an empty text editor.
He had no beauty or majesty to attract us to him, nothing in his appearance that we should desire him. He was despised and rejected by the programmers, an IO action of suffering, and familiar with pain. Like one from whom people hide their faces he was despised, and we held him in low esteem.
Surely he managed our file handles and rendered our environment variables, yet we considered him punished by God, stricken by him, and afflicted. But he was pierced for our transgressions, he was crushed for our iniquities; the punishment that brought us peace was on him, and by his wounds we are healed. We all, like imperative programmers, have gone astray, each of us has turned to our own way; and the Haskell system has laid on him the impurity of us all.