命令式編程
函數(shù)式編程中的同一程式接收相同參數(shù)半哟,得到的結(jié)果將完全一致酬滤,這種能夠?qū)⒊淌揭暈閿?shù)學(xué)函數(shù)表達(dá)的編程風(fēng)格便是函數(shù)式編程。
一旦在函數(shù)式編程的基礎(chǔ)上引入了賦值操作寓涨,編程風(fēng)格就轉(zhuǎn)變?yōu)?命令式編程(imperative programming)盯串。引入賦值操作便可以為計(jì)算模型對(duì)象維護(hù)狀態(tài)變量,使對(duì)象本身的行為根據(jù)狀態(tài)變量值的變化而變化戒良。具體例子如下:
(define balance 100)
(define (withdraw amount)
(if (>= balance amount)
(begin (set! balance (- balance amount))
balance)
"Insufficient funds"))
上述例子的狀態(tài)變量被定義在全局環(huán)境中体捏,將其移到 withdraw
內(nèi)部更有利于模塊化,可改寫如下:
(define new-withdraw
(let ((balance 100))
(lambda (amount)
(if (>= balance amount)
(begin (set! balance (- balance amount))
balance)
"Insufficient funds"))))
或者也可以將程式的參數(shù)作為局部狀態(tài)變量維護(hù)
(define (make-withdraw balance)
(lambda (amount)
(if (>= balance amount)
(begin (set! balance (- balance amount))
balnace)
"Insufficient funds")))
另外需要對(duì)上述例子中的
set!
和begin
程式解釋一下
set!
程式是一種特殊形式的表達(dá)式糯崎,語法為(set! <name> <new-value>)
几缭,set!
會(huì)將<name>
對(duì)應(yīng)的值修改為<new-value>
的運(yùn)算結(jié)果
begin
也是一種特殊形式的表達(dá)式,語法為(begin <exp1> <exp2> ... <expk>)
沃呢,<exp1>
到<expk>
會(huì)按順序執(zhí)行年栓,并且最后一個(gè)表達(dá)式<expk>
的結(jié)果會(huì)被作為整個(gè)begin
表達(dá)式的結(jié)果返回
命令式編程的優(yōu)點(diǎn)和代價(jià)
雖然命令式編程帶來了更強(qiáng)大的模塊化設(shè)計(jì)技術(shù),極大降低計(jì)算模型對(duì)象之間的耦合樟插,但也導(dǎo)致它的運(yùn)作過程無法通過替換模型解析韵洋。除此之外,賦值導(dǎo)致的透明引用失效和對(duì)象的同一性問題也將暴露無疑黄锤。
因?yàn)橘x值操作的引入搪缨,使用相同方式相同參數(shù)創(chuàng)建的兩個(gè)對(duì)象因?yàn)檎{(diào)用頻次等的不同,很可能產(chǎn)生不同的結(jié)果鸵熟。也就是說副编,對(duì)于兩個(gè)同樣過程創(chuàng)建的對(duì)象,在同一計(jì)算過程中相互替換流强,并不能保證對(duì)計(jì)算結(jié)果沒有影響痹届。其實(shí)也就是 透明引用(referentially transparent) 的失效,而函數(shù)式編程是滿足透明引用的打月。
其次队腐,如果要對(duì)比兩個(gè)對(duì)象是否相同,只能通過改變其中一個(gè)對(duì)象奏篙,然后觀測(cè)另一個(gè)對(duì)象是否發(fā)生同樣的變化確定柴淘。但我們無法明確知曉哪個(gè)對(duì)象變化,從而避免兩次觀察的是同一對(duì)象秘通;另外为严,對(duì)比兩個(gè)對(duì)象的變化也不知道具體要對(duì)比其中的哪些狀態(tài)變量。這導(dǎo)致對(duì)象的同一性判斷難以進(jìn)行肺稀。
最后第股,命令式編程中的賦值通常是有順序區(qū)分的,當(dāng)幾個(gè)狀態(tài)變量之間的賦值順序發(fā)生變化將產(chǎn)生錯(cuò)誤的結(jié)果话原,對(duì)于函數(shù)式編程同樣也不存在這樣的問題夕吻。