【问题标题】:What's the reason of marking a recursive function as rec in F#?在 F# 中将递归函数标记为 rec 的原因是什么?
【发布时间】:2011-04-13 23:15:11
【问题描述】:

我不确定这是否是一个愚蠢的问题,但我正在阅读 VS 2010 附带的教程,并且有这样的功能:

let rec factorial n = if n=0 then 1 else n * factorial (n-1)

这个递归函数被rec关键字标记的原因是什么?

是不是让编译器确信它是递归的,所以可以进行某些优化?

如果你排除它会发生什么?

【问题讨论】:

标签: function f# recursion


【解决方案1】:

这可能是有益的:

let Main() =
    let f(x) = 
        printfn "original f: %d" x
    let f(x) =
    //let rec f(x) =
        printfn "entered new f: %d" x
        if x > 0 then
            f(x-1)
        else
            printfn "done"
    f(3)
Main()

打印出来的

entered new f: 3
original f: 2

现在,如果我们注释掉 let 并取消注释 let rec,那么它会打印出来

entered new f: 3
entered new f: 2
entered new f: 1
entered new f: 0
done

所以从这个角度来看,这只是名称绑定; let rec 立即将标识符放入作用域(在此示例中,遮盖了先前的 f),而 let 仅在定义其主体后才将标识符放入作用域。

该规则的动机确实源于与类型推断的交互。

【讨论】:

  • 这是一个关于绑定、阴影和范围界定的非常有教育意义的示例 :-)。
  • +1 但“规则的动机确实源于与类型推断的交互”可以做一些澄清。
【解决方案2】:

根据 Chris Smith(在 F# 团队工作)-

通知类型推断系统允许该函数用作类型推断过程的一部分。 rec 允许您在类型推断系统确定函数类型之前调用函数

【讨论】:

  • 否则类型推断系统会陷入死循环?如果这就是原因,那是有道理的。
  • 真的,仅此而已?考虑到这一点,我想知道如果我明确定义所有类型,我是否可以写一个递归函数没有 rec...实验时间!
  • 如果没有rec,您还必须事先定义函数本身。但是你必须先定义函数,因为它在它自己的范围内是不可用的。但首先,您必须定义函数。定义函数后。一旦定义了函数。这需要定义函数。 无限。
  • @cHao:是的,这就是我认为不可行的。
  • Bascally 它允许您在定义它的同时使用它
【解决方案3】:

根据 MSDN,这只是语法上的必要性:

递归函数,函数 称自己,被识别 在 F# 语言中明确显示。这 使正在成为的标识符 定义范围内可用 功能。

http://msdn.microsoft.com/en-us/library/dd233232.aspx

【讨论】:

    【解决方案4】:

    这个递归函数被rec关键字标记的原因是什么?

    告诉编译器在函数体内对函数名的任何使用都会递归引用它,而不是指向先前定义的同名值。

    编译器是否可以确保它是递归的,从而可以进行某些优化?

    没有。

    如果你排除它会发生什么?

    您将失去定义的函数在其函数体中引用自身的能力,并获得引用先前定义的同名值的能力。

    【讨论】:

    • 你已经在 SO 中写了几个关于这个主题的答案和 cmets,但我发现这个是最有启发性的。它像俳句一样简洁,可以立即掌握其内容,而这部分内容在您更冗长的帖子中丢失了。
    【解决方案5】:

    函数可以是递归的。非rec 函数只知道绑定在它定义的地方,而不是之后(所以它不知道自己)。

    【讨论】:

    • 谢谢查克。你说的绑定是什么意思?类似于范围界定吗?
    • @Joan Venge:绑定基本上是一个变量名及其关联值。在这种情况下,这意味着您不能在其内部使用该函数,因为它只会绑定到名称 let 之后。 let rec 使正在绑定的名称绑定表达式本身可用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-13
    • 1970-01-01
    • 2018-10-10
    • 1970-01-01
    • 2011-01-01
    • 2018-03-12
    • 1970-01-01
    相关资源
    最近更新 更多