我在Don Syme,Adam Granicz和Antonio Cisternino的书Expert F# 4.0, Fourth Edition
中找到了以下内容:
let generateStamp =
let mutable count = 0
(fun () -> count <- count + 1; count)
我无法理解为什么这段代码会创建一个函数:
val generateStamp : (unit -> int)
在我看来,它的签名应该是
val generateStamp : int
例如,以下代码:
let gS =
let mutable count = 0
(printfn "%d" count; count)
创建一个int值:
val gS : int = 0
据我所知,代码(fun () -> count <- count + 1; count)
应首先评估lambda,然后评估count
。因此,generateStamp
的值应该只是count
,因为它在gS
的定义中。我错过了什么?
答案 0 :(得分:5)
在任何F#代码块中,该块中的最后一个表达式将是该块的值。可以使用以下两种方式之一定义块:通过缩进,或在块的表达式之间使用;
。
表达式fun () -> other expressions here
创建一个函数。由于这是let generateStamp =
下代码块中的最后一个表达式,因此该值存储在generateStamp
中。
您的困惑在于您认为fun ()
中的表达式将作为generateStamp
的值的一部分立即进行评估,但它们并非如此。它们定义了fun ()
表达式返回的匿名函数的 body 。你完全正确的是在那段代码中,count
是最后一个表达式,所以它是该函数返回的东西。但是fun ()
表达式会创建一个函数,它只会在调用时评估其内容。它不会立即评估其内容。
相比之下,表达式(printfn "%d" count; count)
是一个代码块,其中包含两个表达式。 不是一个函数,因此会立即评估。它的最后一个表达式为count
,因此代码块(printfn "%d" count; count)
的值为count
。由于正在立即评估(printfn "%d" count; count)
块,因此您可以在心理上将其替换为count
。因此gS
的值为count
,而generateStamp
的值是在评估时返回 count
的函数。
答案 1 :(得分:3)
这是句法上的诡计。最后; count
部分实际上是 lambda 的一部分,而不是它之后的下一个表达式。
以下是一些可以解决的简化示例:
let x = 1; 2; 3 // x = 3
let f x = 1; 2; 3 // f is a function
let y = f 5 // y = 3, result of calling function "f"
let f = fun x -> 1; 2; 3 // Equivalent to the previous definition of "f"
let y = f 5 // y = 3, same as above
let f =
fun x -> 1; 2; 3 // Still equivalent
let y = f 5 // y = 3, same as above
let f =
let z = 5
fun x -> 1; 2; 3 // Still equivalent
let y = f 5 // y = 3, same as above
// Your original example. See the similarity?
let generateStamp =
let mutable count = 0
fun () -> count <- count + 1; count
现在,如果您希望将count
作为generateStamp
的返回值,则需要将其放在parens之外或下一行:
// The following two definitions will make "generateStamp" have type "int"
let generateStamp =
let mutable count = 0
(fun () -> count <- count + 1); count
let generateStamp =
let mutable count = 0
(fun () -> count <- count + 1)
count