函式式程式設計和命令式程式設計

2022-09-16 08:18:14 字數 2005 閱讀 6974

所謂命令式程式設計,是以命令為主的,給機器提供一條又一條的命令序列讓其原封不動的執行。程式執行的效率取決於執行命令的數量。因此才會出現大o表示法等等表示時間空間複雜度的符號。

而函式式語言並不是通常意義上理解的「通過函式的變換進行程式設計」。注意到純的函式式語言中是沒有變數的(沒有可以改變的東西,所有的東西在定義以後就都是不變的),那麼這樣的東西有什麼好處呢?就比如,如果所有的東西都是不變的,那麼我們又怎麼進行程式設計呢?

實際上,我們在函式式程式設計中進行構建的是實體與實體之間的關係。在這種意義上,lisp雖然不是純粹的函式式程式設計,但是也算是函式式程式設計一員。使用這種定義,大多數提供了原生的list支援的指令碼語言也可以算混合了函式式語言的功能,但是這不是函式式語言的精髓。知其然,還要知其所以然。我們既然已經有了精確自然的命令式程式設計,又為什麼還需要函式式程式設計呢?我們舉個小例子。

int fab(int n)

這是用c語言寫的求斐波那契數列的第n項的程式,相應的haskell**是這樣的:

fab :: (num a) => a -> a

fab n = if n == 1 || n == 2 then 1 else fab(n - 1) + fab(n - 2)

看上去差不多對不對?但是這兩個程式在執行的效率方面有著天差地別的差距。為什麼呢?c語言是標準的命令式程式語言。因此對於你寫下的每一行語句,c程式會原封不動地機械地去執行。如果想效率提高,你必須自己去分析程式,去人工地減少程式中執行的語句的數量。具體到這個c程式,我們注意到在每次函式呼叫時,都會產生兩個新的函式呼叫。這時,實際產生的函式呼叫的數目是指數級別的!比方說,我們寫fab(5),實際的執行結果是:

fab(5)

fab(4)

fab(3)

fab(2)

fab(1)

fab(2)

fab(3)

fab(2)

fab(1)

我們看到,fab(3)被求值了兩遍。為了計算fab(5),我們實際執行了8次函式呼叫。

那麼函式式語言呢?我們說過,函式式語言裡面是沒有變數的。換句話說,所有的東西都是不變的。因此在執行fab(5)的時候,過程是這樣的:

fab(5)

fab(4)

fab(3)

fab(2)

fab(1)

fab(3)

總共只有五次應用。注意我說的是應用而不是呼叫。因為函式式語言裡的函式本意並不是命令式語言裡面的「呼叫」或者「執行子程式」的語義,而是「函式與函式之間的關係」的意思。比如fab函式**現的兩次fab的應用,實際上說明要計算fab函式,必須先計算後續的兩個fab函式。這並不存在呼叫的過程。因為所有的計算都是靜態的。haskell可以認為所有的fab都是已知的。因此實際上所有遇到的fab函式,haskell只是實際地計算一次,然後就快取了結果。

本質上,這代表了我們提供給函式式語言的程式其實並不是一行一行的「命令」,而只是對資料變換的說明。這樣函式式語言可以深入這些說明中,尋找這些說明中冗餘的共性,從而進行優化。這就是函式式語言並不需要精心設計就會比命令式語言高效的秘密。命令式語言當然也可以進行這種優化,但是因為命令式語言是有邊界效應的。而且大部分情況下都是利用邊界效應進行計算,因此很難推廣這種優化,只有少數幾種窺孔優化能取得效果。

放到這個例子上,因為本質上我們兩次的fab應用是重疊的。haskell發現了這個特點,於是將兩次fab的結果快取下來(注意,能快取結果的必要條件是這個函式返回的值是不會變的!而這是函式式語言主要的特性)。如果後續的計算需要用到這兩次fab的結果,就不需要再次重複計算,而只是直接提取結果就可以了。這就是上面幾乎完全一樣的兩個程式效率相差如此之大的主要原因。

函式式語言有這樣的優勢,那麼函式式語言有沒有缺陷呢?當然是有的。函式式語言不如命令式語言那麼純粹。和機器一一對應,這在某些情形下會導致更差的效率和更低的開發效率。對計算模型不斷深入的了解會縮短這兩者之間的差距。然而,一定要注意命令式語言是植根於馮·諾依曼體系的,一旦新的體系產生了革命性的改變。那麼命令式語言就不會再適用,而只能通過模擬的方法進行執行,到那個時候,函式式語言和命令式語言的地位就會完全顛倒過來,當然這並不是我們目前需要考慮的問題,但是在現在稍微了解一點函式式語言程式設計的思想是十分重要的。

宣告式程式設計和命令式程式設計

宣告式程式設計是一種程式設計正規化,它關注的是你要做什麼 what 而不是如何做 how 也就是你只需要告訴 機器 你想要的是什麼 what 讓機器想出如何去做 how 舉例 想要顯示乙個p標籤 this is a textp 查詢學生中年齡大於18對的學生的資訊 select from stude...

函式式程式設計和響應式程式設計

在程式開發中,a b c 賦值之後,b或者c的值變化後,a的值不會跟著變化。響應式程式設計目標就是,如果b或者c的數值發生變化,a的數值會同時發生變化。函式式程式設計是一系列被不公平對待的程式設計思想的保護傘,它的核心思想是,它是一種將程式看成是數學方法的求值 不會改變狀態 不會產生 後面我們馬上會...

命令式和符號式程式設計

命令式程式舉例 def add a,b return a b def fancy func a,b,c,d e add a,b f add c,d g add e,f return g fancy func 1,2,3,4 輸出 在執行語句e add a,b 時,python會做加法運算並將結果儲存...