副作用 (プログラム)
プログラミングにおいて、式の評価による作用には、主たる作用とそれ以外の副作用(side effect)とがある[1][2]。 式は、評価値を得ること(※関数では「引数を受け取り値を返す」と表現する)が主たる作用とされ、それ以外のコンピュータの論理的状態(ローカル環境以外の状態変数の値)を変化させる作用を副作用という[3][4][5]。
副作用の例としては、グローバル変数や静的ローカル変数の変更、ファイルの読み書きなどのI/O実行、などがある。 一方、高水準言語における、正弦、余弦、平方根などの数学関数では、関数内でノーマルなローカル変数の変更ぐらいしか伴わないため、副作用がない[6]。
なお、コンピュータの論理的状態(ローカル環境以外の状態)を変化させる機能、つまり副作用を起こす機能は、それ以降で得られる結果に影響を与える。
手始めに、与えられた数字を二倍して返す機能"double
"があるとする。これは主たる作用しかなく、副作用のない例である。
double: x -> 2*x 例: 4 <- double: 2
このような機能では次のことが成立する。
- 同じ条件を与えれば必ず同じ結果が得られる
- 他のいかなる機能の結果にも影響を与えない
このような性質を参照透過性という[7]。参照透過な機能はそれ自身状態を持たないことで、副作用とは縁がない。
一方、状態を持つ機能"add
"を考える。add
が、機能内部からグローバル変数eを参照し、それを増加させて返すものとすれば:
add: x -> e:e+x 例: e: 1 2 <- add:1 2 <- e ...
のようになるだろう。このような機能では機能の外側の状態を変化させてしまうために、参照透過性の一つ目の仮定が崩れ、また、eを利用する他の機能の結果も変化させるので二つ目の仮定も成立しない。add
は副作用を持つ機能である。
副作用を前提とするノイマン型のアーキテクチャ、つまり、大半のプログラミング言語では、add
のようなグローバル変数への破壊的代入、参照渡しされた引数に対するいわゆる“破壊的操作”、そしてインスタンス(レシーバ)に対する破壊的メソッドなどがある。一方、関数型言語では原則として副作用を存在しないものとみなし、モナドなどの手法で抽象化している。
機能が副作用を持たないことの利点は、いかなる状況でも常に同じ結果が得られるために数理論理学に基づく形式的な検証ができ、状況依存でのバグの発生が抑えられ、宣言型プログラミングができるということである[8]。反面、副作用を持たない言語設計はノイマン型アーキテクチャと反りが合わず、効率の点で不利になることが多い。また、単純な逐次処理を行う場合は状態を中心に命令的な思考をした方が扱いやすい場合がある。このためLISPやMLなどは原則として関数型ながら、副作用を許容する設計になっている。
脚注
[編集]- ^ トランジスタ技術 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日確認]
- ^ Spuler, David A.; Sajeev, A. S. M. (January 1994). "Compiler Detection of Function Call Side Effects" (Document). James Cook University. CiteSeerx: 10.1.1.70.2096.
The term Side effect refers to the modification of the nonlocal environment. Generally this happens when a function (or a procedure) modifies a global variable or arguments passed by reference parameters. But here are other ways in which the nonlocal environment can be modified. We consider the following causes of side effects through a function call: 1. Performing I/O. 2. Modifying global variables. 3. Modifying local permanent variables (like static variables in C). 4. Modifying an argument passed by reference. 5. Modifying a local variable, either automatic or static, of a function higher up in the function call sequence (usually via a pointer).
- ^ ドイツ語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日確認
- ^ 厳密に言えば計算途上におけるコンピュータの物理的状態は変化しているし、OSやメモリ状態といった他のレベルでは参照透過性は崩れているかもしれない。しかし「この機能が考える世界」にはそのような変化は存在しないものとして仮想化される。
- ^ ダイクストラは構造化プログラミングでほぼ同等の主張を述べている。副作用の問題は関数型言語に特有というわけではない。