我试图了解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.这是我在这里做错了吗?
试着运行这个:
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
一次并将结果值分配1
给firstCounter
- 当然,如果你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)
现在,每次调用createCounter
new ref
-cell时都会创建并返回一个函数来增加并返回它 - 所以每次调用都会得到一个带有上下文的新计数器,你可以像addCounter
以前一样使用它们