副作用 (プログラム)

プログラミングにおいて、式の評価による作用には、主たる作用とそれ以外の副作用(side effect)とがあるトランジスタ技術 CQ出版社プログラム言語論 筑波大学。
式は、評価値を得ること(※関数では「引数を受け取り値を返す」と表現する）が主たる作用とされ、それ以外のコンピュータの論理的状態(ローカル環境以外の状態変数の値)を変化させる作用を副作用というCクイックリファレンス第二版 P64 オライリー・ジャパン英語wikipediaのSide effect(computer_science)の項目を参考。「In computer science, an operation, function or expression is said to have a side effect if it modifies some state variable value(s) outside its local environment, that is to say has an observable effect besides returning a value (the main effect) to the invoker of the operation. 」の記述。2020/10/09日確認]。

副作用の例としては、グローバル変数や静的ローカル変数の変更、ファイルの読み書きなどのI/O実行、などがある。
一方、高水準言語における、正弦、余弦、平方根などの数学関数では、関数内でノーマルなローカル変数の変更ぐらいしか伴わないため、副作用がないドイツ語wikipediaの Wirkung (Informatik) の項目を参考。そのなかの Programmiersprachen という項に「In den meisten Programmiersprachen kann die Auswertung eines Ausdrucks eine spezifizierte Wirkung haben. Ausdrücke und Funktionen können entweder wirkungsbehaftet oder wirkungsfrei sein. Zur Gruppe der Funktionen mit Wirkung gehören beispielsweise in der Regel alle, die mit der Ein- oder Ausgabe von Daten zu tun haben. Wirkungsfreie Funktionen in Hochsprachen sind etwa mathematische Funktionen wie Sinus, Kosinus oder Quadratwurzel.」という説明。2020/10/09日確認。

なお、コンピュータの論理的状態(ローカル環境以外の状態)を変化させる機能、つまり副作用を起こす機能は、それ以降で得られる結果に影響を与える。
手始めに、与えられた数字を二倍して返す機能"double"があるとする。これは主たる作用しかなく、副作用のない例である。

 double: x -> 2*x
 例:
 4 <- double: 2

このような機能では次のことが成立する。
 同じ条件を与えれば必ず同じ結果が得られる
 他のいかなる機能の結果にも影響を与えない
このような性質を参照透過性という厳密に言えば計算途上におけるコンピュータの物理的状態は変化しているし、OSやメモリ状態といった他のレベルでは参照透過性は崩れているかもしれない。しかし「この機能が考える世界」にはそのような変化は存在しないものとして仮想化される。。参照透過な機能はそれ自身状態を持たないことで、副作用とは縁がない。

一方、状態を持つ機能"add"を考える。addが、機能内部からグローバル変数eを参照し、それを増加させて返すものとすれば:

 add: x -> e:e+x
 例:
 e: 1
 2 <- add:1
 2 <- e
 ...

のようになるだろう。このような機能では機能の外側の状態を変化させてしまうために、参照透過性の一つ目の仮定が崩れ、また、eを利用する他の機能の結果も変化させるので二つ目の仮定も成立しない。addは副作用を持つ機能である。

副作用を前提とするノイマン型のアーキテクチャ、つまり、大半のプログラミング言語では、addのようなグローバル変数への破壊的代入、参照渡しされた引数に対するいわゆる“破壊的操作”、そしてインスタンス(レシーバ)に対する破壊的メソッドなどがある。一方、関数型言語では原則として副作用を存在しないものとみなし、モナドなどの手法で抽象化している。

機能が副作用を持たないことの利点は、いかなる状況でも常に同じ結果が得られるために数理論理学に基づく形式的な検証ができ、状況依存でのバグの発生が抑えられ、宣言型プログラミングができるということであるダイクストラは構造化プログラミングでほぼ同等の主張を述べている。副作用の問題は関数型言語に特有というわけではない。。反面、副作用を持たない言語設計はノイマン型アーキテクチャと反りが合わず、効率の点で不利になることが多い。また、単純な逐次処理を行う場合は状態を中心に命令的な思考をした方が扱いやすい場合がある。このためLISPやMLなどは原則として関数型ながら、副作用を許容する設計になっている。

 脚注 

 関連項目 
 イミュータブル

Category:プログラミング言語理論
Category:プログラミングパラダイム