これについてはこれ以上説明しません。説明を探してみます。
これは、大規模なコードベースをデバッグしてきた私たちの多くに固有のことですが、それを理解するには、十分長い時間、監督者レベルで十分な規模に対処する必要があります。それはポーカーでのポジションの重要性を理解するようなものです。最初は、100万ハンドのハンド履歴を記録し、アウトよりもはるかに多くのお金を獲得したことに気づくまで、すべてのターンの最後に最後に行くのは、それほど有益な利点ではないようです。
とはいえ、ローカル変数への変更は副作用であるという考えには同意しません。私の見解では、関数はスコープ外で何も変更しなければ副作用を引き起こしません。つまり、関数が触れたり改ざんしたりしても、コールスタックの下にあるものや、関数自体が取得しなかったメモリやリソースには影響しません。 。
一般に、想像できる最も完璧なテスト手順を持たない複雑で大規模なコードベースで最も難しいのは、永続的な状態管理です。たとえば、ビデオゲームの世界での細かいオブジェクトへのすべての変更は、何千もの関数が、実際にシステム全体の不変式に違反した容疑者の無限のリストの中から絞り込もうとしている(「これは決して起こらないはずです、だれがやったのですか?」)。関数の外で何も変更されていない場合、集中的な誤動作を引き起こす可能性はありません。
もちろん、これはすべての場合に実行できるわけではありません。別のマシンに保存されているデータベースを更新するアプリケーションは、本来、副作用を引き起こすように設計されています。また、ファイルをロードして書き込むように設計されているアプリケーションも含まれています。しかし、たとえば、不変のデータ構造の豊富なライブラリがあり、この考え方をさらに取り入れれば、多くの関数や多くのプログラムで副作用なしに実行できることはまだまだたくさんあります。
おかしなことに、John Carmackは、最も微調整されたCコーディングの時代から始まったにもかかわらず、LISPと不変性の可能性に飛びついています。Cを今でもよく使っていますが、私も同じようなことをしています。これは、何年にもわたってデバッグを行い、複雑で大規模なシステム全体を監督者レベルから推論しようと努めてきた実用主義者の性質だと思います。関数呼び出しの最も複雑な相互接続されたグラフ間で変更されている複雑な永続状態がたくさんある場合、驚くほど堅牢でバグが大幅に少ないものでも、何か問題が角を曲がっていることに不安を感じることがあります。数百万行のコード。すべての単一のインターフェースが単体テストでテストされ、すべて合格したとしても、
実際には、関数型プログラミングでは関数の理解が難しくなることがよくあります。それでも、特に複雑な再帰的なロジックでは、脳がねじれたり結び目になったりします。しかし、関数型言語で記述されたいくつかの関数を理解することに関連するすべての知的オーバーヘッドは、永続的な状態が数万の関数にわたって変化する複雑なシステムのそれよりも小さく、副作用を引き起こす各関数の合計が合計になります。全体としてのシステム全体の正確さについての推論の複雑さ。
関数に副作用を回避させるために、純粋な関数型言語は必要ありません。関数で変更されたローカル状態は、副作用for
としてカウントされません。たとえば、関数にローカルなループカウンター変数は副作用としてカウントされません。私は今日、可能な限り副作用を回避することを目的としてCコードを作成し、残りのデータが浅いコピーされている間に部分的に変更できる不変でスレッドセーフなデータ構造のライブラリを自分で考案しました。私のシステムの正しさについてはかなりの理由があります。その意味で私は著者に強く反対します。少なくともミッションクリティカルなソフトウェアのCおよびC ++では、関数は、関数の外部の世界に影響を与える可能性のあるものに触れない場合、副作用がないと文書化できます。