引数のない関数に定期的なメモ化を実装しようとしています。
let mutable superVersion = 1
type Memoize() =
member this.m f =
let cache = ref 0
let version = ref 0
let returnValue() =
if !version = superVersion then
!cache
else
System.Console.WriteLine(!cache)
cache := f()
System.Console.WriteLine(!cache)
version := superVersion
!cache
returnValue()
let simpleFunction() = 10 + 5 // Could be some mutable data here
let aFunction() =
let Mem = new Memoize()
let myFunc() = simpleFunction() + 1
Mem.m myFunc
考え方は単純です。このプログラムにデータが入ると、superVersion が 1 ずつ増加します。このように、すべての関数を再計算する必要がありますが、それは新しいデータが入ってきたときだけです。その後、多くの後の関数は以前の関数に基づいて構築でき、以前の関数が再計算されることはありません。この方法では、イベントは必要ありません。
今、私はプログラミング、特に F# にひどく慣れていません。だから私にはわかりませんが、これらの関数を重ねてたくさん構築すると、スタックオーバーフローか何かが発生しますか?
私がやろうとしているのは、イベントなどを使用して正しい順序で物事を計算することについてあまり心配する必要のないデータ調査です。したがって、Excel を除いて Excel のようなもので、リンク (依存関係) の前のセルが変更された場合にのみ計算されます。
ですから、この問題について何らかの情報を得たいと思っています。ただし、ここで主な質問に移ります。
次に aFunction() を呼び出すと、バージョンとキャッシュの両方が計算されてから 0 にリセットされます。2 つのコンソール書き込み行を配置したことがわかります。最初の値は 0 で、2 番目の値は 16 です。(superVersion を変更せずに) aFunction を再度呼び出すと、両方で 16 を取得する代わりに、まったく同じ結果が得られます。キャッシュが 0 にリセットされるのはなぜですか?
本当にありがとう。
編集:私が選んだ答えのように、関数が何をするのかを本当に忘れていました。彼らは使用されると自分の体を呼びます。そのため、すべてがリセットされます。クラスを実装するべき場所に集中しすぎていました。
私がやりたいことの正しい実装は次のようになります。
type Cell(f) =
let mem = Memoize()
let _Value() = mem.m f
member this.Value = _Value()
次に、各関数について、または今私が呼んでいるように、cell. cell の新しいインスタンスを作成し、必要な計算 (関数) を渡すだけです。私はクラスにいるので、Memoize() は一度だけ作成され、その状態が保存されます。John Palmer の回答に見られる Memoizeの新しい実装を使用します。ただし、最初に選択した参照をミュータブルに変更しました。その方が効率的だと思います。