26

我一直认为,在 F# 中,我们需要rec为每个递归函数使用关键字,例如:

let rec factorial = function
| 0 -> 1
| k when k > 0 ->  k * (factorial (k - 1))
| failwith "oops!"

今天我在玩 F#,我想出了一个类似于以下的代码:

let MyRecordType =
    { Something     : float;
      SomethingElse : int }
    with
        static member factorial = function
            | 0 -> 1
            | k when k > 0 ->  k * (MyRecordType.factorial (k - 1))
            | failwith "oops!"

如您所见,我刚刚定义了一个递归函数,但起初我犯了一个错误:我忘记通过关键字将函数声明为递归。rec

但令我惊讶的是它编译!还有更多:如果你添加了rec关键字,那就是语法错误!

type MyRecordType =
    { (* ... *) }
    with
        // syntax error:
        static member rec factorial = function
        (* ... *)

我用谷歌搜索了一个解释,但什么也没得到。在 MSDN 文档中,我在页面外找不到关于递归函数rec的关键字的任何提及,并且截至 2010 年 1 月 3 日,它没有提及我要询问的情况。

完全相同的事情发生在非静态成员身上。

那么,为什么rec在记录类型的成员函数上使用关键字会出现语法错误?

4

2 回答 2

20

所有“成员”函数在它们定义的类型中都是隐含的“rec”。

于 2010-01-04T14:56:59.953 回答
17

'let rec' 不是定义递归函数,而是定义环境中的绑定,其中包括要绑定的当前变量的绑定。您也可以使用'let rec' 来定义例如无限列表。通常,您不希望绑定包含在环境中,因为您可能希望使用相同名称访问较早的变量。

当您定义静态成员函数阶乘时,您不是在寻找变量“阶乘”的绑定,而是寻找类型“MyRecordType”(在环境中作为类型定义),如果它碰巧有一个名为“阶乘”的静态成员函数,它有。

于 2010-01-03T19:53:27.127 回答