どの様な話?
往年のシャープ MZ-80C上で動いたLisp 1.5インタプリタでは、純粋関数しか使えませんでした。
それが何を意味するかと言うと、
- (関数内部で使用する)値を、
- (関数内部の処理順に)的確に、順番と種類(アトム or リスト)を違えず、
- (関数内部の)状態を全て予測し(実行時の実際の状態が現れる前に)、
- 実行前に全ての準備が完了し、実行時に過不足無く与える、
必要が有ると言う事です。
まるでユニットテストのプログラムの問題(手が止まる原因)そのものです。
これは現代的なモナド(別名:単なる自己関手の圏におけるモノイド対象)が入力でも同じ困難となると思います。
また、関数型プログラミングで言う"高階関数*1"を持ち出そうとも、その困難の僅かでも緩和されたりしないと思います。
Lisp 1.5の事情
Lisp 1.5は複雑な純粋関数を作ろうとすると、入れ子にするより有りませんでした。
後の「より実用的な」Lispで見られる、
- 複数の関数を順番に実行し、最後の関数の結果を、その結果とする
- 変数に値を書き込み、読み出しが出来る
の様な機能が(まだ)無かったからです。
すでに関数型のプログラム言語(Lisp 1.5)が有ったのに、後から手続き型風味Lisp言語が出来たのだと思います。(関数型の方が前!!!)
そして、これが核心的事実ですが、
(複雑なものを作ろうと関数を)入れ子にした途端、
純粋関数の為に必要な入力値の作り方が、比較も愚かなほど困難になりました。
テストを書き易くするには
テストを書き易くするには、
- 純粋関数の入れ子は良く無い
- 純粋関数にしたいなら、手続き型プログラミングにするべき
(純粋関数+関数型プログラミングと言うのは愚の骨頂)
です。手続き型プログラミングなら、
- 純粋関数の入れ子無しに、複雑なものが作れる
からです。Lisp言語の発展の過程を見てもこの流れが本筋だと思います。
- より良い✖️より良い = 悪い
なのは世の常です。
結論
これからも「テストが書き辛い」事でプログラミングが嫌いになる人は存在し続けることでしょう。
*1:射を対象とせず、射を射のまま取り扱う以上、どんな明確な定義をしようとも、関数型プログラミングで言う"高階関数"は一階関数と強い意味で同値、としか思えない