検証の敵。「副作用」とは、結局何なのか
はじめに ── 検証の難しさの中心に座る「副作用」
先日、弊社の ttyfky と bun が、サンフランシスコで開催された AI Engineer World's Fair 2026 に参加しました。 ttyfky はカンファレンス全体の概観からEvals と Loops、Software Factoryまで一連の記事にまとめており、bun も現地の様子を伝える参加記を書いております。
なかでも ttyfky の一連の記事を貫いていたのは、Anthropic のキーノートで語られた "Building is easier, generating value is still hard" ── 作ることは易しくなった、しかし価値を生むことは依然として難しい ── という認識です。 実際、生成AIはコードを書くだけでなく、要求を整理し、テストを書き、ログを読んで運用に手を貸すところまで来ております。 それでも価値を生むことは難しいままであり、開発のボトルネックは「生成」から「検証」へと移りつつある、と語られています。
さて、検証を難しくしているものは何でしょうか。 テストのためにモックを用意するのも、環境によって結果の変わる壊れやすいテストに悩まされるのも、思い返せばたいてい「副作用」まわりの話ではないでしょうか。 外部APIを呼ぶから偽物が要る。データベースに書き込むから後始末が要る。時刻に依存するから結果がぶれる。 検証の難しさの中心には、いつもこの現象が座っています。 検証の敵、と呼びたくもなります。
しかし、そもそもこの「副作用」とは一体何なのでしょうか。 日常語の「副作用」は、薬の副作用のように、望んでいないのに付いてくる作用を指します。 ですが、データベースへの書き込みも時刻の取得も、多くのソフトウェアにとっては、望んでいない作用どころか仕事の本体そのものではないでしょうか。 この、呼び名と実態のずれた「副作用」には、定式化された名前が与えられています。 その名は、計算効果(computational effect)1です。 当記事では、この概念を借りて、「副作用」という現象を捉え直していきます。
「副作用」は、計算効果の集まりだった
ソフトウェアが、単なる入出力の集まりであってくれたら、どれほど扱いやすかったでしょうか。 入力を与えれば決まった出力が返り、それ以外には何も起きない。 そんな部品だけで組み上がっているなら、話は単純です。
ですが、現実のソフトウェアを構成する関数は、それ以上のことをします。 現在時刻を読み、例外を投げ、応答を待ち、データベースへ書き込み、ログを吐きます。 値を計算して返すこと以外に関数が引き起こす、こうした「何か」を、私たちは「副作用」と漠然と呼んできました。
冒頭で名前だけ紹介した「計算効果」は、まさにこの「何か」を指す言葉です。 Gordon Plotkin と John Power は、2002年の論文で、この現象の具体例を次のように挙げています2。
Examples of computational effects are: exceptions, interactive input/output, nondeterminism, probabilistic nondeterminism, side-effects and continuations.
訳すと「計算効果の例としては、例外、対話的入出力、非決定性、確率的非決定性、副作用、継続が挙げられる」となります。 ここで目を留めたいのは、私たちが「副作用」と一括りに呼んできたものたち ── 例外も、入出力も、状態の書き換え(ここで side-effects と呼ばれている、狭い意味での副作用)も ── が、それぞれ名前を持つ一例として並べられている点です。 つまり、「副作用」と一括りにしてきた現象は、計算効果という一つの枠組みで説明できるのです。 では、この「計算効果」とはそもそも何でしょうか。 同じ論文の冒頭に、以下のように記されています。
Eugenio Moggi, in [14, 16], introduced the idea of giving a unified category theoretic semantics for what he called notions of computation, but which we call computational effects.
訳すと「Eugenio Moggi は、彼の言う『計算の概念(notions of computation)』、すなわち『計算効果(computational effect)』に、圏論にもとづく統一的な意味論を与えるという着想を持ち込んだ」です。 「計算効果」という概念は、Moggi が1990年前後に築いた、計算を数学的に扱う枠組みの上に立っています(引用中の [14, 16] が、その Moggi の論文です3)。 その Moggi が意味論の道具に選んだものこそ、関数型プログラミングの話題でしばしば名前だけ耳にする、あのモナドです4。 Moggi の論文の題名は "Notions of Computation and Monads"、Plotkin と Power の論文の題名は "Notions of Computation Determine Monads" ── どちらにも、計算の概念とモナドが並んでいます。 (モナドそのものの中身には、当記事では立ち入りません) 「副作用」は、モナドという数学の言葉で定式化できる、計算効果の集まりだったのです。
私たちは毎日、計算効果を扱っていた
「定式化された」と言われても、机上の話に聞こえるかもしれません。 ですが、私たちは「計算効果」という言葉を知るずっと前から、定式化された計算効果と毎日付き合っています。
try-catch は、例外という計算効果を扱うための構文です。
例外を投げる場所と、それを受け止めて始末をつける場所とを、分けて書けます。
async/await は、非同期という計算効果を、上から下へ読み下せる形で扱うための構文です。
どちらも、特定の計算効果を簡単に扱えるように、プログラミング言語が用意したインターフェースです。
計算効果という言葉を知ってから、こうした慣れ親しんだ構文が、少し違って見えるようになりました。 特定の計算効果を名指しで扱う構文を、私たちは毎日使っていたのです。
隠れた計算効果を、どう見つけるか
そう気づくと、次はその逆が気になります。 関数の奥でこっそりデータベースに書き込む、グローバルな状態を書き換える ── 構文にも型にも現れない計算効果は、どうすれば見つけられるのでしょうか。
一つの答えは、機械に見つけさせることです。 現象がきちんと定義され、従うべきルールが与えられているのなら、それを静的解析の対象にできる可能性が開かれます。 実際、プログラムがどんな計算効果を持つかを型システムで追跡する「エフェクトシステム(effect system)」という研究の系譜があり、この語が登場したのは、Moggi の定式化よりもさらに早い1988年のことです5。 今日でも Koka のような言語が、関数の型に「この関数はどんな計算効果を起こすか」を書けるように設計されています。 「副作用があるかもしれない」という注意書きは、これまで人間が気をつけるしかありませんでした。 定式化の先には、それを型として持ち回り、コンパイラに確かめさせるという地平が広がっています。
もっとも、あらゆる計算効果を型で追い切る道は、現実にはかなり険しいようです。 性能面の課題も多いと聞きますし、理論の側も今なお動き続けているようです6。 ですから、多くの言語が状態やログや時刻といった計算効果を型に出さないままにしているのも、無理からぬことに思えます。
だとすると当面、型の外に広がる領域は、人間が受け持つことになります。 型に現れない計算効果を見つけたとき、「ここは計算効果が漏れ出る場所だから、検証のときは気をつけよう」と、自分から察知できるようになります。 検証の時代にこの概念を知っておく実利は、まずここにあるのではないでしょうか。
おわりに
当記事では、検証の難しさの中心に座る「副作用」を、「計算効果」という定式化された概念として捉え直してきました。
漠然とした一語だった「副作用」は、計算効果の集まりでした。
私たちが毎日使う try-catch や async/await は特定の計算効果を扱う構文であり、そして型に現れない計算効果を見分ける仕事は、いまのところ人間に委ねられています。
AIによってソフトウェア開発の取り組み方が変わっていくなかでも、ソフトウェアが外の世界に触れるかぎり、計算効果という現象そのものはなくなりません。 むしろ、生成が速く易しくなるほどボトルネックは検証へ寄っていくのですから、この現象を見分ける目は、これまで以上に問われていくのかもしれません。 使い慣れた「副作用」という言葉を、今度口にするとき ── それがどの計算効果なのか、少しだけ見分けたくならないでしょうか。
最後になりましたが、当記事で辿った整理は、Moggi 氏、Plotkin 氏、Power 氏が築き上げてくださった仕事の入り口を、私なりになぞったものです。訳語「計算効果」は勝股審也氏の仕事から拝借しました。この場を借りて、感謝申し上げます。
冒頭で紹介した一連の記事からも伝わるように、Belong は AI 時代のソフトウェア開発に果敢に挑んでいます。興味を持たれた方は、ぜひ Belong で一緒に働いてみませんか?弊社エンジニアリングチームの情報はエンジニアリングチーム紹介ページをご覧ください。
Footnotes
-
computational effect の訳語「計算効果」は、勝股審也氏による『圏論の歩き方』第5章「モナドと計算効果」(日本評論社、2015)から拝借した。 ↩
-
Gordon Plotkin and John Power, "Notions of Computation Determine Monads," in FoSSaCS 2002, LNCS 2303, Springer, pp. 342–356. 当記事で引用した二箇所は、いずれも同論文の序文にある。正直に言えば、私はその先を読み通せていない。それでも、序文だけで「副作用」の見え方が変わるくらいの収穫はあった。 ↩
-
Eugenio Moggi, "Notions of Computation and Monads," Information and Computation 93(1), pp. 55–92, 1991. 会議版は "Computational Lambda-Calculus and Monads," in LICS 1989. ↩
-
正確には、両論文で使われるのは単なるモナドではなく、strength と呼ばれる構造を添えた「強モナド(strong monad)」である(Moggi 1991, Definition 3.2)。私に言えるのは定義がそこにあることまでで、その先に興味が湧いた方は、ぜひ原論文にあたってほしい。 ↩
-
J. M. Lucassen and D. K. Gifford, "Polymorphic Effect Systems," in POPL 1988, pp. 47–57. "effect system" という語の起源とされる論文。概念の萌芽はさらに、同著者らによる "Integrating Functional and Imperative Programming," in LFP 1986 まで遡れる。 ↩
-
たとえば、計算効果と対をなす「コエフェクト(coeffect)」という概念があり、両者を統一的に扱う枠組みが研究されている。Marco Gaboardi, Shin-ya Katsumata, Dominic Orchard, Flavien Breuvart, and Tarmo Uustalu, "Combining Effects and Coeffects via Grading," in ICFP 2016. ↩