ループを関数型の流儀で

不変性はいわば流行(こちらを参照)ですが、初心者にとっては概念を理解するのが難しいかもしれません。値を変えずにどうやってプログラムが何かをするのでしょうか。私は関数型プログラミング(FP)の専門家でもこの概念の提唱者でもありませんが、何らかの基礎を説明できればと思います。

不変性とは「変えられない」という意味で、Haskellのような言語は実際には変数ではなく定数しか知りません。値を変更するには、古い値から派生した新しい値のコピーを作成する必要があります。古い値は決して変わりません。しかし、どうやってループを書くのでしょう?

まずはJSでの典型的な例を見てみましょう:

let i
for (i=0; i<5; i++)
  console.log("the value is "+i)

同じコード行が変数iを増分しながら複数回実行され、iは「変更」されます。変更に何が悪いのでしょうか?正直なところ、何もありません。ループはほとんどのプログラミング言語の非常に基本的な操作であり、実装が容易です。仮想のアセンブラ言語では、ループはこのように見えるでしょう:

      set 0 -> ADR_I
LBL1  call console.log(ADR_I)
      INC ADR_I
      COMPARE ADR_I, 5
      JMP_IFNOT --> LBL1

これらはすべて変数(またはアドレス)を変更することによって機能します。では、変数がないループはどのように構築されるのでしょうか?Haskellで推薦される方法の1つは再帰です。この概念はJavascriptでも使うことができます:

function loop(n) {
    if (n > 1) 
        loop(n - 1)
    console.log("the value is "+n)
}

ループは条件に達するまで自身を再帰的に呼び出します。その後、最も低い値からログが始まりますので、以下のようになります:

loop(5)
the value is 1
the value is 2
the value is 3
the value is 4
the value is 5

これはプログラマにとって何か利点がありますか?「関数型プログラマ」であれば、変更なしで解決策が得られて幸せかもしれません。しかし、本当に何も変更していないでしょうか?舞台裏ではスタックをメモリとして使用しています。これが起こることです:

loop(5) -->
  loop(4) -->
    loop(3) -->
      loop(2) -->
        loop(1) -->
        console.log("the value is "+1)
      console.log("the value is "+2)
    console.log("the value is "+3)
  console.log("the value is "+4)
console.log("the value is "+5)<br><br>こちらの記事はdev.toの良い記事を日本人向けに翻訳しています。<br>[https://dev.to/efpage/loops-the-functional-way-2jio](https://dev.to/efpage/loops-the-functional-way-2jio)