遞迴函式(一):開篇
遞迴函式(二):編寫遞迴函式的思路和技巧
遞迴函式(三):歸納原理
遞迴函式(四):全函式與計算的可終止性
遞迴函式(五):遞迴集與遞迴可列舉集
遞迴函式(六):最多有多少個程式
遞迴函式(七):不動點運算元
遞迴函式(八):偏序結構
遞迴函式(九):最小不動點定理
上文我們討論了集合上的關係,還討論了數學歸納法的一種普遍形式,稱為良基歸納法,
它建立在集合上的良基關係之上。
本文開始討論函式,我們將回顧函式的定義,
然後解釋什麼是全函式(total function),什麼是部分函式(partial function)。
我們會看到,在證明乙個遞迴函式是全函式時,
良基歸納法起到了重要作用。
在分析學中,人們似乎很少關心函式的完全性,
只關心它的連續性,可導性,可微性與可積性,等等。
而在電腦科學領域中,人們更在意計算的可終止性,
因此乙個函式在某個點是否有定義將經常被提及。
程式中定義的函式,往往對應於某個集合上的數學函式,
為了描述程式的非終止性,就得擴充這個數學函式的定義域和值域。
為了理解這些事情,我們先要從函式的定義開始。
集合\(a,b\)上的關係,是笛卡爾積\(atimes b\)的乙個子集。
而函式\(f:arightarrow b\),則是集合\(a,b\)上的一種特殊關係,
它要求\(a\)中的每乙個元素,都有\(b\)中唯一確定的元素與之對應。
其中,集合\(a\)稱為函式\(f\)的定義域,集合\(b\)稱為函式的值域。
函式是我們熟悉的概念,這裡只是提到了它本質上是集合上的乙個關係。
(1)部分函式(partial function)
如果\(f\)是從\(a\)到\(b\)的二元關係,且\(forall ain a\),\(f(a)=varnothing \)或\(lbrace brbrace \),
則稱\(f\)是從\(a\)到\(b\)的部分函式,或\(a\)上的部分函式。
其中,如果\(f(a)=lbrace brbrace\),則稱\(f(a)\)有定義,記為\(f(a)downarrow \),
也稱\(b\)為\(f\)在\(a\)點的函式值,記為\(f(a)=b\)。
如果\(f(a)=varnothing \),則稱\(f(a)\)無定義,記為\(f(a)uparrow \)。
(2)全函式(total function)
如果\(forall ain a\)都有\(f(a)downarrow \),則稱\(f\)是\(a\)上的全函式,
此時,可以記為\(f:arightarrow b\)。
可見,我們熟悉的函式,指是全函式。
值得注意的是,部分函式的定義已經包含了我們學過的「函式」的定義,
後文中,我們提到的「函式」如果不強調它的完全性的話,都泛指部分函式。
部分函式在電腦科學中是非常重要的,
因為對於每乙個\(ain a\),乙個演算法可以表示為,計算出集合\(b\)中與之對應元素的過程,
這個演算法可能對於某些值\(ain a\)不會終止,而這種情況是很常見的。
例如:
f :: int -> int
f 1 = 1
f n = n + f(n-2)
這樣定義的函式f
,對應了數學上的乙個部分函式\(f\),它只在某些情況下有意義,
只有當n
是奇數時,我們才能得到終止性的結果。
而當n
是偶數時,演算法會無限的遞迴下去,直到堆疊溢位。
因此,將int
解釋為整數集\(n\),將f :: int -> int
解釋為整數集上的函式,似乎是有問題的。
因為,\(f(2)\)並不是乙個整數,它的計算不能終止。
為了描述非終止性,就需要對整數集進行擴充,
我們給整數集加上乙個特殊元素「\(perp \)」,稱為bottom,來表示非終止性,
而將f :: int -> int
解釋為集合\(ncup lbrace perp rbrace \)上乙個的數學函式。
像這種通過構造表達程式含義的數學物件,來對程式進行分析的方法,來自指稱語義學。
指稱語義中,人們會區分函式的嚴格性,乙個函式稱為嚴格的(strict),
如果接受乙個非終止的輸入表示式,函式的計算仍然不會終止,
即,\(f(perp )=perp \)。
否則,稱函式為不嚴格的(non-strict)。
我們看到在程式中使用遞迴,可能會導致非終止性的計算,而有些遞迴又不會。
這是為什麼呢?
我們可以從遞迴函式論中找到一些線索。
遞迴函式論是和圖靈機以及\(lambda \)演算相等價的計算模型,它從另乙個角度刻畫了可計算性。
可計算性是乙個有趣的話題,後續文章中,我們會詳細討論。
在遞迴函式論中,人們把函式劃分為了3個層次,
原始遞迴函式,遞迴函式,和其他的不能用遞迴函式表示的「函式」。
這些函式集合的範圍越來越大。
本文我們先介紹原始遞迴函式,
為此,我們需要先定義兩種運算。
(1)合成運算
設\(f\)是\(k\)元部分函式,\(g_1,g_2,cdots ,g_k\)是\(k\)個\(n\)元部分函式,令,
\(h(x_1,cdots ,x_n)=f(g_1(x_1,cdots ,x_n),cdots ,g_k(x_1,cdots ,x_n))\)
則稱\(h\)是由\(f\)和\(g_1,g_2,cdots ,g_k\),經過合成運算得到的。
(2)原始遞迴運算
設\(f\)是乙個\(n\)元全函式,\(g\)是\(n+2\)元全函式,令,
\(h(x_1,cdots ,x_n,0)=f(x_1,cdots ,x_n)\)
\(h(x_1,cdots ,x_n,t+1)=g(t,h(x_1,cdots ,x_n,t),x_1,cdots ,x_n)\)
則稱\(h\)是由\(f\)和\(g\)經過原始遞迴運算得到的。
於是,我們就可以定義原始遞迴函式了。
設初始函式包括,
(1)零函式\(n(x)=0\)
(2)後繼函式\(s(x)=x+1\)
(3)投影函式\(u^n_i(x_1,cdots ,x_n)=x_i\),\(ileqslant ileqslant n\)
則由初始函式經過有限次合成運算和原始遞迴運算得到的函式,稱為原始遞迴函式。
原始遞迴函式有以下這些性質:
由原始遞迴函式經過合成或原始遞迴得到的函式仍為原始遞迴函式,
因此,原始遞迴函式的集合在合成與原始遞迴運算下是封閉的。
此外,每乙個原始遞迴函式都是全函式。
這是因為合成運算雖然是在部分函式上定義的,
但是如果\(f\)和\(g_1,g_2,cdots ,g_k\)是全函式,那麼\(h\)也一定是全函式。
另一方面,在進行原始遞迴運算時,如果\(f\)和\(g\)是全函式,則\(h\)也一定是全函式,
這是因為原始遞迴運算在\(h\)的引數集上的定義了乙個良基關係,由良基歸納法可證,\(h\)是全函式。
本文介紹了全函式與部分函式,以及計算可終止性相關的概念,
我們對程式中函式的指稱,進行了定義域和值域的擴充,
隨後,我們進一步了解了原始遞迴函式,以及它的完全性,良基歸納法起到了關鍵作用。
下文,我們將深入到可計算性理論,
討論部分可計算函式和可計算函式的區別,討論遞迴函式與原始遞迴函式的關係,
引出遞迴可列舉集這個重要的概念。
function (mathematics))
strict function
可計算性與計算複雜性導引
數的計算 遞迴與函式自呼叫演算法
題目描述description 我們要求找出具有下列性質數的個數 包含輸入的自然數n 先輸入乙個自然數n n 1000 然後對此自然數按照如下方法進行處理 1.不作任何處理 2.在它的左邊加上乙個自然數,但該自然數不能超過原數的一半 3.加上數後,繼續按此規則進行處理,直到不能再加自然數為止.輸入輸...
可重入函式與不可重入函式的區別
自 可重入函式可以做這樣的基本定義 重入意味著這個函式可以重複進入,可以被並行呼叫,可以被中斷,它只使用自身棧上的資料變數,它不依賴於任務環境,在多任務排程過程中,它是安全的,不必擔心資料出錯。不可重入函式基本上與可重入函式有相反的定義了 不可重入,意味著不可被並行排程,否則會產生不可預料的結果,這...
python中的匿名函式與遞迴函式
匿名函式 無需使用def來命名的函式 用到關鍵字lambda 求最大值的匿名函式 max num lambda num1 num2 num1 if num1 num2 else num2 求和sum num lambda num1 num2 num1 num2 多項和 遞迴函式 自己呼叫自己的函式,...