F#:尝试memoize成员函数重置每次调用缓存?

Pau*_*ing 3 f# caching member memoization

我正在尝试记住一个类的成员函数,但每次调用该成员(由另一个成员)时,它都会创建一个全新的缓存和"memoized"函数.

member x.internal_dec_rates = 
        let cache = new Dictionary< Basis*(DateTime option), float*float>()
        fun (basis:Basis) (tl:DateTime option) ->
            match cache.TryGetValue((basis,tl)) with
            | true, (sgl_mux, sgl_lps) -> (sgl_mux, sgl_lps)
            | _ ->
                let (sgl_mux, sgl_lps) =
                    (* Bunch of stuff *)
                cache.Add((basis,tl),(sgl_mux,sgl_lps))
                sgl_mux,sgl_lps
Run Code Online (Sandbox Code Playgroud)

我在"真实世界功能编程"中使用清单10.5作为模型.我尝试过使用memoization高阶函数,但没有用.上面的列表直接内置了memoization.

问题是,当我称之为例如

member x.px (basis:Basis) (tl: DateTime option) = 
        let (q,l) = (x.internal_dec_rates basis tl)
        let (q2,l2) = (x.internal_dec_rates basis tl)
        (exp -q)*(1.-l)
Run Code Online (Sandbox Code Playgroud)

执行进入'let cache = ...'行,击败了整点.我放入(q2,l2)行以确保它不是范围问题,但它似乎不是.

事实上,我使用Petricek的代码作为成员函数进行了测试,似乎有同样的问题:

// Not a member function
let memo1 f =
    let cache = new Dictionary<_,_>()
    (fun x ->
        match cache.TryGetValue(x) with
        | true, v -> v
        | _ -> let v = f x
               cache.Add(x,v)
               v
    )

member x.factorial = memo1(fun y->
    if (y<=0) then 1 else y*x.factorial(y-1))
Run Code Online (Sandbox Code Playgroud)

即使x.factorial的内部递归似乎也为每个级别设置了一个新的"缓存".

我做错了什么,我怎样才能做到这一点?

Dan*_*iel 6

在回答你对杰克答案的评论时,这不必变得单调乏味.给出memoize功能:

let memoize f =
  let cache = Dictionary()
  fun x ->
    match cache.TryGetValue(x) with
    | true, v -> v
    | _ -> 
      let v = f x
      cache.Add(x, v)
      v
Run Code Online (Sandbox Code Playgroud)

将每个函数定义为let-bound值并从方法中返回它们:

type T() as x =
  let internalDecRates = memoize <| fun (basis: Basis, tl: DateTime option) ->
    (* compute result *)
    Unchecked.defaultof<float * float>

  let px = memoize <| fun (basis, tl) ->
    let (q,l) = x.InternalDecRates(basis, tl)
    let (q2,l2) = x.InternalDecRates(basis, tl)
    (exp -q)*(1.-l)

  member x.InternalDecRates = internalDecRates
  member x.Px = px
Run Code Online (Sandbox Code Playgroud)

唯一的"样板"是let绑定和调用memoize.

编辑:正如kvb所指出的,在F#3.0中,自动属性允许更简洁的解决方案:

type T() as x =
  member val InternalDecRates = memoize <| fun (basis: Basis, tl: DateTime option) ->
    (* compute result *)
    Unchecked.defaultof<float * float>

  member val Px = memoize <| fun (basis, tl) ->
    let (q,l) = x.InternalDecRates(basis, tl)
    let (q2,l2) = x.InternalDecRates(basis, tl)
    (exp -q)*(1.-l)
Run Code Online (Sandbox Code Playgroud)


Bri*_*ian 5

我在这看到很多很长的答案; 简短的回答是

member x.P = code()
Run Code Online (Sandbox Code Playgroud)

定义一个P具有每次访问时运行的getter的属性.您需要将缓存创建移动到类的构造函数中,以便它只运行一次.code()P