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

时间:2014-09-14 16:57:48

标签: f#


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

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()

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

1 个答案:

答案 0 :(得分: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()

您的版本执行此操作:它会调用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"

这里发生了什么

现在每当你调用createCounter时,都会创建一个新的ref - 单元格,并且会返回一个增加并返回此函数的函数 - 所以每次调用都会得到一个带有上下文的新计数器,你可以使用它那些在你之前使用addCounter的那些