You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

F#子类中抽象函数的Memoization实现难题

解决F#子类重写抽象方法时的Memoization问题

问题原因

  1. 直接调用Memoize无效:每次调用重写的MemoSubClassSlow100方法时,都会重新执行Memoize SlowNumber100InSubClass t,相当于每次都新建一个带空字典的闭包,无法复用之前计算的结果。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 21:09:21