誰かがこの改良に興味を持っている場合は、追加のアキュムレータパラメータをスレッド化することで、Lenのソリューションよりもパフォーマンスの面で少し優れた方法を実行できます。
アイデアはstore : 'a btree -> 'a option list
、ツリーを取得してリストを生成する関数から、パラメーターとして渡された既存のstore' : 'a btree -> 'a option list -> 'a option list
リストにツリーの要素を追加する関数に移動することです。
let rec store' t acc = match t with
| L x -> Some x :: acc
| N (a, b) ->
store' a (store' b (None :: acc))
この定義では、要素は、最初に一時リストを作成するために使用され、次にオペレーターstore a
を介して最終結果に2回追加されるのではなく、最終結果リストに1回だけ追加されます。(@)
t
前に書き込むacc
と、リスト内の最後の要素の順序が直感的にわかるため、パラメーターの順序は重要です。の要素は、に既に存在する要素のt
前になりますacc
。これにより、ケースを非常に自然に読み取ることができます。結果には、最初に、、次に、、次にの要素N
が含まれることが簡単にわかります。a
b
None
acc
最後に、もちろん、次store
の観点から定義することができstore'
ます。
let store t = store' t []
最初の定義を2番目の定義内にラップし(この「低レベル」関数をユーザーに公開したくない場合)、外部定義と同じ名前を付けるのが通例です(競合しません)。再帰的ではないため、内部スコープには入りません):
let store t =
let rec store t acc = match t with
| L x -> Some x :: acc
| N (a, b) ->
store a (store b (None :: acc))
in store t []
もちろん、この定義がレンの定義よりも「優れている」かどうかは、評価基準が何であるかによって異なります。Lenのソリューションはより短く、読みやすく、元の問題をより厳密にマッピングします。
(厳密なリストの代わりに遅延列挙を使用することで、両方の長所を活用できる場合がありますが、それはまた別の話です。)