为什么闭包在成员函数上不能正常工作?

时间:2012-10-16 09:48:08

标签: f# closures

如果我正常工作,它会按预期工作(缓存结果):

      let help = let tmp = printfn "oh no"
                           1+1
                 fun () -> tmp
      help ()
      help ()

      >oh no

但是,如果我将其作为成员函数,它将不再有效:

    type test =
        { a: float }
        member x.help = 
                  let tmp = printfn "oh no"
                            x.a * 2.
                  fun () -> tmp
        member x.b = x.help ()

    let t = { a = 1. }
    t.b
    t.b

    >oh no
    >oh no

3 个答案:

答案 0 :(得分:3)

正如@John所说,根据F# specification,您的help财产相当于

type test =
     { a: float }
     member x.help with get () = 
              let tmp = printfn "oh no"
                        x.a * 2.
              fun () -> tmp

这是伪装的函数,因此每次调用属性时都会计算一个新的tmp值。

要确保一次调用该属性,您可以创建一个私有帮助器并在类型扩充中使用它:

type test = { a: float }

/// Create a private helper to make sure 'help' is evaluate once
let private help = 
    printfn "oh no"              
    fun x -> x.a * 2.

/// Create a property using the private helper
type test with
     member x.b = help x

答案 1 :(得分:2)

这是真正的区别 -

  let help = let tmp = printfn "oh no"
                       1+1
             fun () -> tmp
  printfn "here"
  help ()
  help ()

打印

here
oh no

所以,在它被召唤之前,实际上已经形成了帮助。

在第二种情况下,我们可以阅读规范(8.13.1)

  

此外,以下两个成员是等价的:

     

staticopt成员ident.opt ident = expr

     

staticopt成员ident.opt ident with get()= expr

即。你的x.b实际上是一个每次调用帮助的函数

答案 2 :(得分:0)

方法始终具有隐式this参数,因此它们始终是函数。在您的情况下,x是OO代码中的原始参数中不存在的参数。