在F#中将递归函数标记为rec的原因是什么?

发布于 2024-09-24 02:41:11 字数 288 浏览 6 评论 0原文

我不确定这是否是一个愚蠢的问题,但我正在浏览 VS 2010 附带的教程,并且有一个这样的函数:

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

What's the Reason of this recursive function to be marked with the rec keywords?

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

如果排除它会发生什么?

I am not sure if this is a stupid question but I was going through the tutorial that comes with VS 2010 and there is a function like this:

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

What's the reason of this recursive function to be marked with the rec keyword?

Is it so that the compiler is assured of it being recursive so can do certain optimizations?

What happens if you exclude it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

此岸叶落 2024-10-01 02:41:11

这可能具有启发性:

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

Now,然后它会打印So 从这个角度来看,它只是关于名称绑定; let rec 立即将标识符放入作用域中(在本例中,隐藏了前面的 f),而 let 仅将标识符放入作用域中体被定义。

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

This might be instructive:

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()

That prints

entered new f: 3
original f: 2

Now if we comment out let and uncomment let rec, then it prints

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

So from that point of view, it's just about name binding; let rec puts the identifier in scope immediately (in this example, shadowing the previous f), whereas let puts the identifier in scope only after its body is defined.

The motivation for the rule does stem from interactions with type inference.

丿*梦醉红颜 2024-10-01 02:41:11

根据 Chris Smith(F# 团队工作)的说法,

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

According to Chris Smith (works on the F# team) -

It's to inform the type inference system to allow the function to be used as part of the type inference process. rec allows you to call the function before the type inference system has determined the function's type

烟花肆意 2024-10-01 02:41:11

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

递归函数,函数
称自己为身份
明确地以 F# 语言表示。这
使正在存在的标识符
定义在范围内可用
功能。

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

According to the MSDN, it's only a syntatic necessity:

Recursive functions, functions that
call themselves, are identified
explicitly in the F# language. This
makes the identifer that is being
defined available in the scope of the
function.

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

﹏半生如梦愿梦如真 2024-10-01 02:41:11

这个递归函数为什么要用rec关键字来标记?

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

这样编译器就可以确保它是递归的,以便可以进行某些优化吗?

不。

如果排除它会发生什么?

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

What's the reason of this recursive function to be marked with the rec keyword?

To tell the compiler that any uses of the function name inside the body of the function refer to it recursively rather than to a previously-defined value of the same name.

Is it so that the compiler is assured of it being recursive so can do certain optimizations?

No.

What happens if you exclude it?

You lose the ability for the function you are defining to refer to itself in its function body and gain the ability to refer to previously-defined values of the same name.

初雪 2024-10-01 02:41:11

这是必要的,以便函数可以递归。非 rec 函数仅了解其定义位置处的绑定,而不是其定义位置之后的绑定(因此它不了解其自身)。

It's necessary so that the function can be recursive. A non-rec function only knows about bindings at the place where it's defined, not after (so it doesn't know about itself).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文