副作用

Haskell に副作用はあるのか。
http://d.hatena.ne.jp/kazu-yamamoto/20100607/1275872735

twitter で @ainsophyao さんがこう言っていました。

副作用については、 a=f(x);b=f(x);g(a); というプログラムと a=f(x);b=f(x);g(b); というプログラムが異なるものになりうるか、を定義とすればいいと思う。

私もこの定義はよいと思います。

そしてその続きとして、

そして、Haskell では異なる値になることを ST を使って示します。本当は IO を使いたかったのですが、Haskell 自体では runIO main と書けないので、議論の対象に実行器を含んでいるのか曖昧になり議論が噛み合ないことが多かったのでやめておきます。

念のため書きますが、僕は実行器を含めて議論しています。実行しなくていいのなら、たとえば C の printf("Hello\n") だって、出力はしないので、副作用はないですからね。

とあった。私が思うことは以下。

完全に出遅れましたが、sumii さんと同じで do 記法は糖衣構文でしかない、ということです。

参照透過性という意味での副作用でしたら、参照透過性は「式」の持つ性質なので、文と式の区別をしなくてはいけません。do 記法は全部合わせて一つの式あるいはその一部ですから、そのなかで順序を変えても参照透過性がないことを示しません。
式の中で、順序を変えたら結果が変わるというのは、非可換な演算子が存在する、といっているだけです。


C 言語の printf は、エラーがでると負の数を返すという意味で参照透過性がありません。


参照透過性の問題ではなく、I/O に対しての話ならば、C 言語は高級アセンブリですので、printf は内部にバッファーがあって、そこの状態まで含めて副作用といいたいのでしょう。これはどこまでをその言語とするか、という話だと思います。


エラー処理をしないような C の printf があり他の関数との兼ね合いがなければこれも参照透過性がある、と言っていいと思います。


そのプログラムあるいは関数を繰り返し実行するとメモリーの状態が変化することは起きていますが、それは当然なので副作用とわざわざ呼ぶ理由はどこにもないような。あるいは入出力機能があることを副作用とわざわざ呼ぶのもあまり意味がないと思いませんか。



それと、もしも、IO は命令であるというならば、たとえば、IO (IO a) はどのように解釈するんでしょうか。命令なのか命令書なのかという議論ならば、命令型言語の考え方に影響されて命令と考えるよりは、命令書とするほうがはるかに分かりやすいと思いますよ。