複雑な部分はループです。それから始めましょう。ループは通常、単一の関数で反復を表現することにより、機能的なスタイルに変換されます。反復とは、ループ変数の変換です。
一般的なループの機能的な実装は次のとおりです。
loop : v -> (v -> v) -> (v -> Bool) -> v
loop init iter cond_to_cont =
if cond_to_cont init
then loop (iter init) iter cond
else init
(ループ変数の初期値、[ループ変数で]単一の反復を表す関数)(ループを継続するための条件)を取ります。
この例では、配列でループを使用していますが、ループも壊れています。命令型言語のこの機能は、言語自体に組み込まれています。関数型プログラミングでは、このような機能は通常、ライブラリレベルで実装されます。ここに可能な実装があります
module Array (foldlc) where
foldlc : v -> (v -> e -> v) -> (v -> Bool) -> Array e -> v
foldlc init iter cond_to_cont arr =
loop
(init, 0)
(λ (val, next_pos) -> (iter val (at next_pos arr), next_pos + 1))
(λ (val, next_pos) -> and (cond_to_cont val) (next_pos < size arr))
その中に :
外部で見えるループ変数と、この関数が隠す配列内の位置を含む((val、next_pos))ペアを使用します。
反復関数は、一般的なループよりも少し複雑です。このバージョンでは、配列の現在の要素を使用できます。[ カレー形式です。]
このような関数は通常「fold」と呼ばれます。
名前に「l」を入れて、配列の要素の蓄積が左結合方式で行われることを示します。命令型プログラミング言語の習慣を模倣して、配列を低インデックスから高インデックスに反復する。
名前に「c」を付けて、このバージョンのfoldがループを早期に停止するかどうか、いつ停止するかを制御する条件をとることを示します。
もちろん、このようなユーティリティ関数は、使用されている関数型プログラミング言語に同梱されているベースライブラリですぐに利用できる可能性があります。デモ用にここに書きました。
これで、命令型の言語のツールがすべて揃ったので、次に、例の特定の機能を実装します。
ループ内の変数はペアです(「answer」、続行するかどうかをエンコードするブール値)。
iter : (Int, Bool) -> Int -> (Int, Bool)
iter (answer, cont) collection_element =
let new_answer = answer + collection_element
in case new_answer of
10 -> (new_answer, false)
150 -> (new_answer + 100, true)
_ -> (new_answer, true)
新しい「変数」「new_answer」を使用したことに注意してください。これは、関数型プログラミングでは、すでに初期化された「変数」の値を変更できないためです。パフォーマンスについては心配していません。コンパイラがより効率的であると考えた場合、ライフタイム分析を介して 'new'answer'の 'answer'のメモリを再利用できます。
これを以前に開発したループ関数に組み込みます:
doSomeCalc :: Array Int -> Int
doSomeCalc arr = fst (Array.foldlc (0, true) iter snd arr)
ここでの「配列」は、foldlc関数をエクスポートするモジュール名です。
「fist」、「second」は、ペアパラメーターの最初の2番目のコンポーネントを返す関数を表します
fst : (x, y) -> x
snd : (x, y) -> y
この場合、「ポイントフリー」スタイルにより、doSomeCalcの実装の可読性が向上します。
doSomeCalc = Array.foldlc (0, true) iter snd >>> fst
(>>>)は関数構成です: (>>>) : (a -> b) -> (b -> c) -> (a -> c)
上記と同じですが、定義式の両側から「arr」パラメーターのみが残されています。
最後に、ケースのチェック(配列== null)。より良く設計されたプログラミング言語では、しかし基本的な規律がある悪い設計言語でも、存在しないことを表現するためにオプションの型を使用します。これは、関数型プログラミングとはあまり関係がなく、最終的に問題となるので、対処しません。
break
とのreturn answer
ことで置き換えることができreturn
、ループ内。FPでは、継続を使用してこの早期復帰を実装できます。たとえば、en.wikipedia.org / wiki / Continuation