为什么F#Closure上下文没有评估为新值?

Nai*_*air 2 f#


我试图了解F#中的Closure.基于这里的问题和答案,我的理解是,它是承载上下文的过程.其中一个答案有一个非常简单的解决方案,如下所示

let addCounter = 
    let counter = ref 0
    (fun () -> incr counter; !counter)

[<EntryPoint>]
let main argv =
    let firstCounter = addCounter()
    printfn "%A" firstCounter
    printfn "%A" firstCounter
let k = Console.ReadKey()
Run Code Online (Sandbox Code Playgroud)

我创建了一个名为firstCounter的高阶函数,我期望第一个输出为1,第二个输出为2.但是当我运行时,我得到的答案都是1.这是我在这里做错了吗?

Car*_*ten 5

试着运行这个:

let addCounter = 
    let counter = ref 0
    (fun () -> incr counter; !counter)

[<EntryPoint>]
let main argv =
    printfn "%d" (addCounter ())
    printfn "%d" (addCounter ())

let k = Console.ReadKey()
Run Code Online (Sandbox Code Playgroud)

你的版本执行此操作:它调用addCounter一次并将结果值分配1firstCounter- 当然,如果你firstCounter多次评估(实际上只是一个整数),你会得到相同的答案.

具有闭包的部分counter是由函数捕获的,fun () -> incr counter; !counter并且在F#中使用它是相当常见的事情(如果可以使用闭包,则需要类来捕获状态 - 实际上类(及其方法)和闭包有很多共同之处!

你的其他问题

如果你想动态创建计数器,你可以这样做:

let createCounter() = 
    let counter = ref 0
    (fun () -> incr counter; !counter)

[<EntryPoint>]
let main argv =
    let c1 = createCounter()
    let c2 = createCounter()
    printfn "%d" (c1 ()) // -> "1"
    printfn "%d" (c2 ()) // -> "1"
    printfn "%d" (c1 ()) // -> "2"
    printfn "%d" (c1 ()) // -> "3"
    printfn "%d" (c2 ()) // -> "2"
Run Code Online (Sandbox Code Playgroud)

这里发生了什么

现在,每次调用createCounternew ref-cell时都会创建并返回一个函数来增加并返回它 - 所以每次调用都会得到一个带有上下文的新计数器,你可以像addCounter以前一样使用它们

  • 我添加了一点来回答这个问题 - 它确实很容易做到(在正确的地方做一个简单的`()`) (2认同)