J C*_*per 8 syntax f# function
所以我刚刚完成了我的第一个F#程序,我唯一的功能背景是对Haskell 的一点知识(读:没有真正生成任何程序).
在经历了一些令人难以置信的行为后,我开始意识到F#区分了:
prepareDeck = allSuits |> List.collect generateCards |> shuffle
Run Code Online (Sandbox Code Playgroud)
和
prepareDeck() = allSuits |> List.collect generateCards |> shuffle
Run Code Online (Sandbox Code Playgroud)
我注意到它"缓存"了前者,如果再次调用则不会重新计算它,而它将后者视为正常函数.你不能分辨出所讨论的功能是否有副作用,显然,但是我shuffle
做到了!
这应该是常识吗?我还没有在任何教程材料上看到它.原因只是解析器中的一个弱点,有点像你在使用它之前必须声明一个函数?
Jul*_*iet 15
大多数F#材料确实解释了模块中的所有顶级语句都是从声明自上而下执行的.换句话说,您声明的不是函数,而是程序运行时绑定一次的值.
查看反映的代码确实很有帮助.我有一个简单的文件:
let juliet = "awesome"
let juliet2() = "awesome"
Run Code Online (Sandbox Code Playgroud)
编译后的代码如下所示:
public static string juliet
{
[CompilerGenerated, DebuggerNonUserCode]
get
{
return "awesome";
}
}
//...
public static string juliet2()
{
return "awesome";
}
Run Code Online (Sandbox Code Playgroud)
所以一个是静态属性,另一个是函数.这是一个理想的属性,因为想象一下,如果我们有这样的东西:
let x = someLongRunningDatabaseCall()
Run Code Online (Sandbox Code Playgroud)
我们只想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
Run Code Online (Sandbox Code Playgroud)
由于isInNebraska
是一个值,它立即进行评估.恰好它的数据类型是(string -> bool)
,所以它看起来像一个函数.因此,cities
即使我们调用函数1000次,我们也只填充一次.
让我们将该代码与此进行比较:
> 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
Run Code Online (Sandbox Code Playgroud)
糟糕,我们每次调用函数时都会创建一个新的城市集.
因此,价值观和功能之间肯定存在合理和真实的区别.
这就是几乎每种语言都有副作用的方法.
let name = expr
Run Code Online (Sandbox Code Playgroud)
运行代码'now',如果expr
有效果可能会导致副作用.后续引用name
无效.而
let name() = expr
Run Code Online (Sandbox Code Playgroud)
定义一个函数,现在没有效果,并且每次name()
调用时都会评估(并产生效果).