In Tackling the Awkward Squad: monadic input/output, concurrency, exceptions, and foreign-language calls in Haskell, SPJ states:
For example, perhaps the functional program could be a function mapping an input character string to an output string:
main :: String -> String
Now a "wrapper" program, written in (gasp!) C, can get an input string from somewhere [...] apply the function to it, and store the result somewhere [...]
He then goes on to say that this locates the "sinfulness" in the wrapper, and that the trouble with this approach is that one sin leads to another (e.g. more than one input, deleting files, opening sockets etc).
This seems odd to me. I would have thought Haskell would be most powerful, and possibly even most useful, when approached exactly in this fashion. That is, the input is a character string located in a file, and output is a new character string in a new file. If the input string is some mathematical expression concatenated with data, and the output string is (non-Haskell) code, then you can Get Things Done. In other words, why not always treat Haskell programs as translators? (Or as a compiler, but as a translator you can blend genuine I/O into the final executable.)
Regardless of the wisdom of this as a general strategy (I appreciate that some things we might want to get done may not start out as mathematics), my real question is: if this is indeed the approach, can we avoid the IO a
type? Do we need a wrapper in some other language? Does anyone actually do this?