我正在尝试为没有参数的函数实现定期memoization。
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个控制台writelines。在第一个中,值为0,第二个为16.再次调用aFunction(不更改superVersion),得到完全相同的结果,而不是两者都得到16。为什么缓存重置为0?
非常感谢。
编辑:就像我选择的答案让我知道,我真的忘记了功能的作用。他们在使用时称他们的身体。所以一切都重置了。我太专注于他们应该实现一个课程。
我想要做的正确实现将是这样的:
type Cell(f) =
let mem = Memoize()
let _Value() = mem.m f
member this.Value = _Value()
现在对于每个函数,或者我现在正在调用它,单元格。我只是创建一个新的单元格实例并传递我想要的计算(一个函数)。现在因为我在一个类中,Memoize()只创建一次并保存其状态。在John Palmer的回答中使用Memoize的 new 实现。但是我将我最初选择的引用更改为mutables。我认为这更有效率。
答案 0 :(得分:1)
每次调用该函数时,变量都会被重置 - 您需要将它们移到函数之外,如
type Memoize() =
let cache = ref 0
let version = ref 0
member this.m f =
let returnValue() =
if !version = superVersion then
!cache
else
System.Console.WriteLine(!cache)
cache := f()
System.Console.WriteLine(!cache)
version := superVersion
!cache
returnValue()