简体   繁体   English

F#:为什么我必须为不带参数的函数明确指定'unit'?

[英]F#: Why do I have to explicitly specify 'unit' for functions taking no arguments?

So I've just about finished my first F# program, with my only functional background being a little bit of knowledge of Haskell (read: Haven't really produced any programs in it). 所以我刚刚完成了我的第一个F#程序,我唯一的功能背景是对Haskell 的一点知识(读:没有真正生成任何程序)。

After experiencing some boggling behavior, I came to realize that F# makes a differentiation between: 在经历了一些令人难以置信的行为后,我开始意识到F#区分了:

prepareDeck = allSuits |> List.collect generateCards |> shuffle

and

prepareDeck() = allSuits |> List.collect generateCards |> shuffle

I noticed that it "caches" the former, never recalculating it if it's called again, whereas it treats the latter like a normal function. 我注意到它“缓存”了前者,如果再次调用则不会重新计算它,而它将后者视为正常函数。 You can't tell the difference if the function in question doesn't have side effects, obviously, but my shuffle did! 如果有问题的功能没有副作用,你无法区分,显然,但是我的shuffle了!

Was this supposed to be common knowledge? 这应该是常识吗? I haven't seen it mentioned on any tutorial materials yet. 我还没有在任何教程材料上看到它。 Is the reason just a weakness in the parser, kinda like how you have to declare a function before you use it? 原因只是解析器中的一个弱点,有点像你在使用它之前必须声明一个函数?

Most F# material does explain that all top-level statements in a module are executed from top-down on declaration. 大多数F#材料确实解释了模块中的所有顶级语句都是从声明自上而下执行的。 In other words, what you've declared isn't a function, but a value which is bound once when the program runs. 换句话说,您声明的不是函数,而是程序运行时绑定一次的值。

It really helps to see the reflected code. 查看反映的代码确实很有帮助。 I have a simple file: 我有一个简单的文件:

let juliet = "awesome"
let juliet2() = "awesome"

The compiled code looks something like this: 编译后的代码如下所示:

public static string juliet
{
    [CompilerGenerated, DebuggerNonUserCode]
    get
    {
        return "awesome";
    }
}

//...

public static string juliet2()
{
    return "awesome";
}

So one is a static property, the other is a function. 所以一个是静态属性,另一个是函数。 This is a desirable property, because imagine if we had something like this: 这是一个理想的属性,因为想象一下,如果我们有这样的东西:

let x = someLongRunningDatabaseCall()

We only want x to be bound once, we don't want it to invoke database function everytime we access x . 我们只希望x绑定一次,我们不希望它每次访问x调用数据库函数。

Additionally, we can write interesting code like this: 另外,我们可以编写这样有趣的代码:

> 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

Since isInNebraska is a value, its evaluated immediately. 由于isInNebraska是一个值,因此立即进行评估。 It just so happens that its datatype is (string -> bool) , so it looks like a function. 恰好它的数据类型是(string -> bool) ,所以它看起来像一个函数。 As a result, we only fill our cities set once even if we invoke the function 1000 times. 因此,即使我们调用函数1000次,我们也只填充一次设置的cities

Let's compare that code to this: 让我们将该代码与此进行比较:

> 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

Oops, we're creating a new cities set everytime we invoke the function. 糟糕,我们每次调用函数时都会创建一个新的城市集。

So there is definitely a legitimate and real distinction between values and functions. 因此,价值观和功能之间肯定存在合理和真实的区别。

This is how things work in practically every language with side effects. 这就是几乎每种语言都有副作用的方法。

let name = expr

runs the code 'now', and may cause side-effects if expr has effects. 运行代码'now',如果expr ,可能会导致副作用。 Subsequent references to name have no effects. name后续引用没有任何效果。 Whereas

let name() = expr

defines a function, has no effects now, and will evaluate (and have effects) every time name() is invoked. 定义一个函数,现在没有效果,并且每次调用name()时都会评估(并产生效果)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM