IOモナドで副作用的な入出力ができるのは、mainの型がIO aだからだろ?
個人的には、言語ランタイム(mainの呼び出し元)からずりずりケーブル引きずって制御パネルを
持ち歩いているイメージ。
そして、それ(ケーブルを引きずる)を可能にしているのがモナドの代数的性質。
純粋な関数で入出力ができないのはそういうことだと理解している。