F#子类中抽象函数的Memoization实现难题
解决F#子类重写抽象方法时的Memoization问题
问题原因
- 直接调用Memoize无效:每次调用重写的
MemoSubClassSlow100方法时,都会重新执行Memoize SlowNumber100InSubClass t,相当于每次都新建一个带空字典的闭包,无法复用之前计算的结果。 - override val报错:父类定义的是抽象方法(
DateTime->float类型的方法),而override val用于重写抽象属性,二者类型不匹配,因此编译报错。
解决方案
方案一:父类定义抽象属性(函数类型)
把父类的抽象成员改为函数类型的属性,子类用override val直接赋值Memoize后的函数,这样缓存字典会在实例初始化时创建并复用。
修改后的代码:
open System let Memoize f = let dict = Dictionary<_, _>() fun c -> let exists, value = dict.TryGetValue c match exists with | true -> value | _ -> let value = f c dict.Add(c, value) value [<AbstractClass>] type ParentClass() as this = let someparam = DateTime(2022,1,1) let SlowNumber100InParentClass(t) = System.Threading.Thread.Sleep(1000) 100.0 member val MemoParentClassSlow100 = Memoize SlowNumber100InParentClass member this.MultiplyBy2A = (this.MemoParentClassSlow100 someparam) * 2.0 // 将抽象成员改为函数类型的属性 abstract MemoSubClassSlow100: (DateTime -> float) member this.MultiplyBy2B = (this.MemoSubClassSlow100 someparam) * 2.0 type MyClass() as this = inherit ParentClass() let SlowNumber100InSubClass(t) = System.Threading.Thread.Sleep(1000) 100.0 // 用override val重写抽象属性,赋值Memoize后的函数 override val MemoSubClassSlow100 = Memoize SlowNumber100InSubClass [<EntryPoint>] let main args = let x = new MyClass() for i in 1..10 do Console.WriteLine(x.MultiplyBy2A) // 快速输出 for i in 1..10 do Console.WriteLine(x.MultiplyBy2B) // 现在也会快速输出 0
方案二:子类预先缓存Memoize后的函数
在子类中提前创建Memoize后的函数(作为实例级的闭包),然后重写方法时调用这个缓存的函数,确保所有方法调用共享同一个字典。
修改后的代码:
open System let Memoize f = let dict = Dictionary<_, _>() fun c -> let exists, value = dict.TryGetValue c match exists with | true -> value | _ -> let value = f c dict.Add(c, value) value [<AbstractClass>] type ParentClass() as this = let someparam = DateTime(2022,1,1) let SlowNumber100InParentClass(t) = System.Threading.Thread.Sleep(1000) 100.0 member val MemoParentClassSlow100 = Memoize SlowNumber100InParentClass member this.MultiplyBy2A = (this.MemoParentClassSlow100 someparam) * 2.0 abstract MemoSubClassSlow100: DateTime->float member this.MultiplyBy2B = (this.MemoSubClassSlow100 someparam) * 2.0 type MyClass() as this = inherit ParentClass() let SlowNumber100InSubClass(t) = System.Threading.Thread.Sleep(1000) 100.0 // 预先创建Memoize后的函数,作为实例的一部分 let memoizedSlow = Memoize SlowNumber100InSubClass // 重写方法时调用缓存的函数 override this.MemoSubClassSlow100(t) = memoizedSlow t [<EntryPoint>] let main args = let x = new MyClass() for i in 1..10 do Console.WriteLine(x.MultiplyBy2A) // 快速输出 for i in 1..10 do Console.WriteLine(x.MultiplyBy2B) // 现在也会快速输出 0
内容的提问来源于stack exchange,提问作者Eugene
相关产品推荐
相关产品推荐

