在 F# 中是否使用空括号表示没有参数?

In F# Are Empty Parenthesis used to indicate no parameter?

给定此 F# 库代码

来自主要

open FileMaint
let log_file = FileMaint.fm.generate_log_file

来自图书馆

module FileMaint
.
.
.
[<AutoOpen>]
(* return_unique_file_name just returns as close to a unique file name piece based on clock time. *)
module fm =


(* Checks for presense of a file name. *)
    let is_file_present file_name =
        let rc =
            if File.Exists file_name then
                true
            else
                false
        rc

    (* Initialize a log file. *)
    let generate_log_file =
        let log_file_name = 
            if File.Exists(base_log_file) then
                test_and_reset_unique_file_name local_dir base_log_file
            else
                base_log_file

        use fH = new StreamWriter(log_file_name, true)
        fH.WriteLine(generate_time_stamp + ": " + log_file_name + " initialized.")

从我的 "main",我可以进入调用 is_file_present,但我不能进入,也不会 generate_log_file 执行。

然而,在generate_log_file库函数上定义括号后,像这样generate_log_file (),然后调用它,函数执行(我可以进入函数)

因此,当函数没有参数时,空括号似乎表示占位符。对吗?

空括号是类型 unit。此值与任何其他值一样,与数字或字符串没有主要区别。

let a = 5
let b = "abc"
let c = ()

> val a: int = 5
> val b: string = "abc"
> val c: unit = ()

这种类型unit的特殊之处在于它只有一个值,没有其他值。但在其他方面,它就像任何其他类型一样。您可以将它用于函数参数,例如:

let f (u: unit) = ...

但是因为它只有一个值,所以可以将值本身用作参数模式:

let f () = ...

您也可以对其他类型执行此操作:

let g 42 = ...
let h "abc" = ...

这将编译,但它会警告您 int 除了 42 之外还有其他值,并且您还没有定义该函数应该为它们做什么。但是对于 unit 除了 () 之外不能有其他值,所以没有警告。您甚至可以自己制作等效类型:

type T = A
let f A = 42   // no warning here, because A is the only possible value of type T

现在,回到您的示例:在您的原始代码中,generate_log_file 不是函数,而是一个值。它是在初始化期间计算的,当您认为自己是 "calling" 它时,您只是在引用该预先计算的值。没有通话正在进行,因为没有什么可通话的。

它是一个值而不是一个函数的原因是它没有任何参数。是的,这是一个简单的规则:如果你有参数,你就是一个函数;如果没有,你就是一个价值。所以一旦你给它一个参数,它就变成了一个函数,这就是你可以介入的原因。

就目前而言,generate_log_file 的值是在初始化模块 fm 时初始化的值,很可能是在程序集启动期间。如果您有策略地插入 Debugger.Break,这是可调试的。

通过将代码更改为 let generate_log_file () ... generate_log_file 现在是您使用单位值 () 调用的函数,从而更易于调试。

在 F# 中,您总是使用单个值调用函数,() 是类型 unit 的唯一值。

PS.

let generate_log_file () ... 使用参数的模式匹配来避免输入 let generate_log_file (_ : unit) ...。以下也是合法的,尽管有点无用 let generate_log_file 0 ....