何时评估 F# 函数调用;懒惰还是立即?

When are F# function calls evaluated; lazily or immediately?

F# 中的柯里化函数。我知道传递参数子集会产生带有预设的函数。我只是想知道传递所有参数是否有什么不同。例如:

let addTwo x y = x + y
let incr a = addTwo 1
let added = addTwo 2 2

incr 是一个接受一个参数的函数。 added 是一个整数还是一个函数?我可以想象一个实现,其中 "added" 仅在使用时才被延迟评估(就像打开盒子时的薛定谔的猫)。是否可以保证何时执行添加?

added 不是函数;它只是一个计算值并当场绑定到名称。一个函数总是至少需要一个参数;如果没有什么有用的东西可以传递,那将是 unit():

let added () = addTwo 2 2

incr is a function taking one argument. Is added an int or a function?

在本例中,

added 是一个计算结果为 int 的命名绑定。它不是函数。

I can imagine an implementation where "added" is evaluated lazily only on use (like Schroedinger's Cat on opening the box). Is there any guarantee of when the addition is performed?

添加将在生成绑定时立即执行。不涉及懒惰。

作为,可以通过添加参数将added改为绑定函数而不是绑定值,参数可以是unit:

let added () = addTwo 2 2

在这种情况下,它将是一个函数,因此在您调用它之前不会发生加法:

let result = added () // Call the function, bind output to result

F# 是一种 求值 语言,因此像 addTwo 2 2 这样的表达式将立即求值为 int 类型的值。

相比之下,

Haskell 是延迟求值的。像 addTwo 2 2 这样的表达式在需要值之前不会被求值。不过,表达式的类型仍然是单个整数。即便如此,这样的表达式尽管很懒惰,但仍不被视为函数;在 Haskell 中,这种未计算的表达式称为 thunk。这基本上只是意味着“一个尚未评估的任意复杂表达式”。

没有。但有点是。但真的,没有。

你可以构建一个纯函数式语言,它只有函数,没有其他任何东西。 Lambda 演算是一个完整的代数,所以理论就在那里。在这个模型中,added 可以被认为是一个 无参数 函数(与 random() 形成对比,其中有一个类型为单位的参数)。

但 F# 不同。由于它是命令式编程和函数式编程的相当实用的组合,因此结果不是函数 [1]。相反,它是一个值,就像 C# 中的本地值一样。这不是实现细节——它实际上是 F# 规范的一部分。这确实有缺点 - 这意味着它可能有一个模棱两可的定义,其中定义可以是值或函数定义 (14.6.1)。

[1] - 虽然在纯函数式程序中,您无法区分它们 - 这与用缓存值替换函数是一样的,这是完全合法的。