[英]What's the reason of marking a recursive function as rec in F#?
我不確定這是否是一個愚蠢的問題,但我正在閱讀VS 2010附帶的教程,並且有一個這樣的函數:
let rec factorial n = if n=0 then 1 else n * factorial (n-1)
這個遞歸函數用rec關鍵字標記的原因是什么?
這樣編譯器可以確保它是遞歸的,所以可以進行某些優化嗎?
如果排除它會怎么樣?
這可能是有益的:
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
只在定義了body之后才將標識符放在作用域中。
規則的動機源於與類型推斷的交互。
據Chris Smith說(在F#團隊工作) -
通知類型推斷系統允許該函數用作類型推斷過程的一部分。 rec允許您在類型推斷系統確定函數類型之前調用該函數
根據MSDN,它只是一種合成必需品:
遞歸函數,調用自身的函數,在F#語言中明確標識。 這使得在函數范圍內定義的標識符可用。
這個遞歸函數用rec關鍵字標記的原因是什么?
告訴編譯器函數體內函數名的任何使用都是遞歸地引用它而不是先前定義的同名值。
這樣編譯器可以確保它是遞歸的,所以可以進行某些優化嗎?
沒有。
如果排除它會怎么樣?
您失去了定義的函數在其函數體中引用自身的能力,並且能夠引用先前定義的同名值。
這是必要的,以便函數可以遞歸。 非rec
函數只知道它定義的地方的綁定,而不是之后(因此它不了解自身)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.