程式設計正規化
掌握一門語言的語法、工具和技巧固然重要,但那只相當於學會一門兵器的招法,更重要的當然是心法。招法重形,心法重意。得形而忘意,無異捨本逐末;得意而忘形,方能游刃有餘。下面要談的就是一種心法:程式設計正規化。
正規化譯自英文的
paradigm
,也有譯作典範、范型、範例的。如果說每個程式設計者都在創造虛擬世界,那麼程式設計正規化就是他們置身其中自覺不自覺採用的世界觀和方**。簡單講,程式設計正規化就是程式語言的語感。
程式設計是為了解決問題,而解決問題可以有多種視角和思路,其中普適且行之有效的模式被歸結為正規化。由於著眼點和思維方式的不同,相應的正規化自然各有側重和傾向,因此一些正規化常用
『oriented』
來描述。換言之,每種正規化都引導人們帶著某種的傾向去分析問題、解決問題。比如:
object-oriented就是『
物件導向
』的程式設計正規化。
程式設計正規化分類
基本正規化
最基本的兩種程式設計正規化:命令式和宣告式, 其中命令式又稱過程式。通俗點說,命令式程式設計由命令序列組成,即一系列祈使句:
『先做這,再做那
』,強調
『怎麼做』『
已知這,求解那
』,強調
『做什麼
』。學術點說,命令式程式設計是電腦(
von neumann
機)執行機制的抽象,即有序地從記憶體中獲取指令和資料然後去執行;宣告式程式設計是人腦思維方式的抽象,即利用數理邏輯或既定規範
(specification
)對已知條件進行推理運算。
命令式語言是面向機器的,起源於機器語言;宣告式語言則發軔於人工智慧的研究,主要包括函式式語言和邏輯式語言。
起源的不同決定了這兩大類正規化代表著迥然不同的程式設計理念和風格:命令式程式設計是行動導向(
action-oriented
)的,因而演算法是顯性而目標是隱性的;宣告式程式設計是目標驅動(
goal-driven
)的,因而目標是顯性而演算法是隱性的。
示例: c
(命令式):
int factorial(int n)
lisp
(函式式):
(defun factorial(n)
(if (= n 0) 1 // 若n
等於0,則n!等於1
(* n (factorial(- n 1))))) //
否則n!
等於n* (n-1)
prolog
(邏輯式):
// 0! 等於1
factorial(0,1).
// 若m
等於n-1且m!
等於fm且f
等於n*fm
,則n! 等於f
factorial(n,f) :- m is n-1, factorial(m,fm), f is n * fm.
c明確給出了階乘的迭代演算法,而
lisp
僅描述了階乘的遞迴定義,
prolog
則陳述了兩個關於階乘的斷言。
命令式程式設計中的變數本質上是抽象化的記憶體,變數值是該記憶體的儲存內容
。通俗地說,前者好比姓名,所指之人是固定的;後者好比住址,所住之人是變化的。此外,等號在代數中是一種約束,而在許多命令式語言中則表示賦值。
宣告式程式設計讓我們重回數學思維,其中函式式程式設計類似代數中的表示式變換和計算,邏輯式程式設計則類似數理邏輯推理。其中的變數也如數學中的一樣,是抽象符號而非記憶體位址,因此沒有賦值運算,不會產生變數被改寫的***,也不存在記憶體分配和釋放的問題。這既簡化了**,也減少了除錯 。
比較而言,宣告式程式設計重目標、輕過程,專注問題的分析和表達而不致陷入演算法的迷宮,其**也更加簡潔清晰、易於修改和維護。
程式語言的流行程度與其擅長的領域關係密切。宣告式語言擅長基於數理邏輯的應用,如人工智慧、符號處理、資料庫、編譯器等,對基於業務邏輯的、尤其是互動
式或事件驅動型的應用就不那麼得心應手了。而大多數軟體是面向使用者的,互動性強、多為事件驅動、業務邏輯千差萬別,顯然命令式語言在此更有用武之地。
任何語言都難脫命令式或宣告式的窠臼,因此上述三種正規化最為基本。
歸根結底,程式設計是尋求一種機制,將指定的輸入轉化為指定的輸出。 三種正規化對此提供了迥然不同的解決方案:命令式把程式看作乙個自動機,輸入是初始狀態,輸出是最終狀態,程式設計就是設計一系列指令,通過自動機執行以完成狀態轉變;函式式把程式看作乙個數學函式,輸入是自變數,輸出是因變數,程式設計就是設計
一系列函式,通過表示式變換以完成計算;邏輯式把程式看作乙個邏輯證明,輸入是題設,輸出是結論,程式設計就是設計一系列命題,通過邏輯推理以完成證明。繪成
**如下
——」
正規化
程式
輸入
輸出
程式設計
程式執行
命令式
自動機
初始狀態
最終狀態
設計指令
命令執行
函式式數學函式
自變數因變數
設計函式
表示式變換
邏輯式邏輯證明 題設
結論設計命題
邏輯推理
《冒號課堂》目錄
目錄 上篇 程式設計正規化與程式語言第1 課開班導言 1.1開班發言 程式設計師的 4層境界 1.2首輪提問 什麼語言好?1.3語言選擇 合適的就是好的 1.4初識正規化 程式王國中的世界觀與方 1.5開發技術 實用還是時髦?第2 課重要正規化 2.1命令正規化 一切行動聽指揮 2.2宣告正規化 目...
《冒號課堂》學習筆記 OOP 繼承
提倡介面繼承,慎用實現繼承。非抽象類不適宜作基類。為繼承而設計的類應該做到 禁用protected成員域 保證protected成員方法的規範性和穩定性 防止覆蓋的 軟體設計應該兼顧靈活性與穩定性,提倡外靜內動。外靜指保持外部的介面不變,內動指允許內部的實現變動。無論是抽象還是設計模式以及庫 框架 ...
我的《冒號課堂》學習筆記 值與引用(2)語義型別
值與引用 值語義的物件是獨立的,語義的物件卻是允許共享的。由於j a不支援值型別物件,j a程式設計師才更需要加強這方面的意識。語法和語義並不總是一致的 語法上的值型別可能在語義上是引用型別,語法上的引用型別可能在語義上是值型別。永遠不要忘記乙個基本原則 語法只是手段,語義才是目的。為了判斷乙個型別...