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

时间:2016-12-08 21:40:30

标签: f# lazy-evaluation currying

F#中的Curried函数。我得到了一个位,传入一个参数子集产生一个带预设的函数。我只是想知道传递所有参数是否有任何不同。例如:

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

incr是一个带有一个参数的函数。 added是int还是函数?我可以想象一个实现,其中“添加”仅在使用时被懒惰地评估(就像Schroedinger的Cat打开盒子一样)。是否有保证何时进行添加?

4 个答案:

答案 0 :(得分:18)

added不是函数;它只是一个计算出来并在现场绑定到名称的值。一个函数总是至少需要一个参数;如果没有任何有用的内容,那就是unit()

let added () = addTwo 2 2

答案 1 :(得分:12)

  

incr是一个带有一个参数的函数。是添加了一个int还是一个函数?

在这种情况下,

added是一个命名绑定,其值为int。它不是一种功能。

  

我可以想象一个实现,其中"添加"仅在使用时懒惰地评估(如打开盒子时的Schroedinger&Cat;)。是否有保证何时进行添加?

生成绑定时,将立即执行 。没有懒惰。

作为explained by TeaDrivenDev,您可以通过添加参数addedunit更改为绑定函数而不是绑定值:

let added () = addTwo 2 2

在这种情况下,它将是一个函数,所以在你调用它之前不会发生添加:

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

答案 2 :(得分:12)

F#是一种急切评估的语言,因此像addTwo 2 2这样的表达式会立即被评估为int类型的值。

相比之下,哈斯克尔被懒惰地评估了。在需要值之前,不会评估类似addTwo 2 2的表达式。但是,表达式的类型仍然是一个整数。即便如此,这种表达尽管有懒惰,却不被视为一种功能;在Haskell中,这种未经评估的表达式称为 thunk 。这基本上只是意味着“尚未评估的任意复杂表达”。

答案 3 :(得分:2)

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

您可以构建一个只有函数而不包含其他函数的纯函数式语言。 Lambda演算是一个完整的代数,所以理论就在那里。在此模型中,added可以被视为无参数函数(与例如random()相反,其中有一个类型为unit的参数)。

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

[1] - 虽然在一个纯函数式程序中,你无法区分它 - 它只是用一个缓存值代替函数,这是完全合法的。 / p>