大多数 F# 材料确实解释了模块中的所有顶级语句都是在声明时自上而下执行的。也就是说,你声明的不是函数,而是程序运行时绑定一次的值。
查看反映的代码确实很有帮助。我有一个简单的文件:
let juliet = "awesome"
let juliet2() = "awesome"
编译后的代码如下所示:
public static string juliet
{
[CompilerGenerated, DebuggerNonUserCode]
get
{
return "awesome";
}
}
//...
public static string juliet2()
{
return "awesome";
}
所以一个是静态属性,另一个是函数。这是一个理想的属性,因为想象一下如果我们有这样的东西:
let x = someLongRunningDatabaseCall()
我们只希望x被绑定一次,我们不希望它每次访问x时都调用数据库函数。
此外,我们还可以编写如下有趣的代码:
> let isInNebraska =
printfn "Creating cities set"
let cities = set ["Omaha"; "Bellevue"; "Lincoln"; "Papillion"; "La Vista"; "Ralston"]
fun n -> cities.Contains(n);;
Creating cities set
val isInNebraska : (string -> bool)
> isInNebraska "Omaha";;
val it : bool = true
> isInNebraska "Okaloosa";;
val it : bool = false
由于isInNebraska 是一个值,因此立即对其进行评估。它的数据类型恰好是(string -> bool),所以它看起来 像一个函数。因此,即使我们调用该函数 1000 次,我们也只会填充一次 cities 集。
让我们将该代码与此进行比较:
> let isInNebraska2 n =
printfn "Creating cities set"
let cities = set ["Omaha"; "Bellevue"; "Lincoln"; "Papillion"; "La Vista"; "Ralston"]
cities.Contains(n);;
val isInNebraska2 : string -> bool
> isInNebraska2 "Omaha";;
Creating cities set
val it : bool = true
> isInNebraska2 "Okaloosa";;
Creating cities set
val it : bool = false
糟糕,每次调用该函数时,我们都会创建一个新的城市集。
因此,价值和功能之间肯定存在合法和真实的区别。