Mathematicaには、関数呼び出しを書き換えルールとして評価することの副作用としてテーブルを作成するという素敵なトリックがあります。古典的なスローフィボナッチを考えてみましょう
fib[1] = 1
fib[2] = 1
fib[n_] := fib[n-1] + fib[n-2]
最初の2行は、入力1と2のテーブルエントリを作成します。これは、次のように言うのとまったく同じです。
fibTable = {};
fibTable[1] = 1;
fibTable[2] = 1;
JavaScriptで。fib[n_]
Mathematicaの3行目は、「パターン変数n_
をオカレンスの実際の引数に置き換えた後、オカレンスを置き換える書き換えルールをインストールしてください」と述べていfib[n-1] + fib[n-2]
ます。リライターはこの手順を繰り返し、最終的fib[n]
には指数関数的な数のリライト後にの値を生成します。これは、JavaScriptで取得する再帰関数呼び出しフォームと同じです。
function fib(n) {
var result = fibTable[n] || ( fib(n-1) + fib(n-2) );
return result;
}
再帰呼び出しを行う前に、明示的に格納した2つの値について最初にテーブルをチェックすることに注意してください。ルールの表示順序が重要であるため、Mathematicaエバリュエーターはこのチェックを自動的に行います-Mathematicaは最初により具体的なルールをチェックし、後でより一般的なルールをチェックします。そのため、Mathematicaには2つの割り当て形式が=
あり:=
ます。前者は、ルールの定義時に右側を評価できる特定のルール用です。後者は、ルールが適用されるときに右側を評価する必要がある一般的なルール用です。
さて、Mathematicaでは、
fib[4]
に書き直されます
fib[3] + fib[2]
その後に
fib[2] + fib[1] + 1
その後に
1 + 1 + 1
そして最後に3になります。これは、次の書き換えでは変更されません。fib[35]
と言えば、膨大な表現を生成し、メモリをいっぱいにし、CPUを溶かしてしまうことを想像できます。ただし、秘訣は、最終的な書き換えルールを次のように置き換えることです。
fib[n_] := fib[n] = fib[n-1] + fib[n-2]
fib[n_]
これは、「のすべての出現箇所を、の値に新しい特定のルールをインストールし、値をfib[n]
生成する式に置き換えてください」という意味です。これは、ルールベース(値のテーブル)を拡張するため、はるかに高速に実行されます。-実行時。
JavaScriptでも同様にできます
function fib(n) {
var result = fibTable[n] || ( fib(n-1) + fib(n-2) );
fibTable[n] = result;
return result;
}
これは、fibの以前の定義よりもはるかに高速に実行されます。
これは「自動メモ化」と呼ばれます[原文のまま-「メモ化」ではなく、自分でメモを作成する場合の「メモ化」]。
もちろん、現実の世界では、作成されるテーブルのサイズを管理する必要があります。Mathematicaでテーブルを調べるには、
DownValues[fib]
JavaScriptでそれらを検査するには、
fibTable
Node.JSでサポートされているようなREPLで。