为什么这个定义会返回一个函数?

时间:2017-02-24 03:03:47

标签: f#

我在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的定义中。我错过了什么?

2 个答案:

答案 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