関数型プログラミングでループするような制御文で行われていないfor
とwhile
、それが明示的のような関数への呼び出しで行われますmap
、fold
または再帰-内部ループコールをかけ伴うすべてが別の関数内。ループコードがループの外側の変数を変更する場合、この内側のループ関数はスコープ外の変数を操作するため、不純になります。したがって、外部関数全体は純粋ですが、ループはそうではありません。関数型プログラミングのループ構造では、状態を明示的にする必要があります。関数型プログラミングループツールを使用してコードを何かに変換すると、不正確さが明らかになります。
int as_int(char *str)
{
int acc = 0; /* accumulate the partial result */
map(takeWhile(isdigit, str), void function(char *chr) {
acc = acc * 10 + (chr - '0');
});
return acc;
}
(注-この構文は、全体的な考え方を理解するために概算です)
このコードは、acc
スコープの外にある変数を変更する必要があるループ本体の内部関数を使用します。これは不正確です。内側のループ関数は外側のループコンテキストに依存します。同じ文字で複数回呼び出すと、副作用があり、文字のシーケンスで呼び出す順序が重要になります。関数型プログラミングでは、これを純粋な関数にするために、ループの反復間で渡される状態にこの依存関係を明示的に指定する必要がありfold
ます。
int as_int(char *str)
{
return fold(takeWhile(isdigit, str), 0, int function(char *chr, int acc) {
return acc * 10 + (chr - '0');
});
}
fold
は、内部ループ本体に2つの引数の関数を使用します。最初の引数fold
はループしているシーケンス内の項目です。2番目の引数は、内部ループ本体が部分的な結果を作成するために使用する値です。最初のループの反復の場合acc
は0、2番目の場合acc
は最初の内部ループ関数呼び出しが返されたもの、3番目の場合は2番目の内部ループが返されたもの、最後のループはfold
式全体の結果を返します。
これは、プログラムの残りの部分から見たコードの問題ではないことに注意してくださいas_int
。両方の定義は純粋です。違いは、内部ループコードを純粋な関数にすることです。関数型プログラミングが提供する膨大な数のツールを利用して、ループをより宣言的なものに分解できます(takeWhile、fold、filter、mapなどを使用します)。