什麼是命令式編程 (Imperative Programming)?javascript
命令機器如何作事情,強調細節實現html
java、c、c++等都屬此類。java
「這些語言的特徵在於,寫出的代碼除了表現出「什麼(What)」是你想作的事情以外,更多的代碼則表現出實現的細節,也就是「如何(How)」完成工做。這部分代碼有時候多到掩蓋了咱們原來問題的解決方案。好比,你會在代碼裏寫for循環,if語句,a等於b,i加一等等,這體現出機器如何處理數據。」c++
什麼是聲明式編程(Declarative Programming)?程序員
聲明式編程告訴機器作什麼,至於怎麼作到的,你能夠不用管。算法
表明語言:prolog
特色:你只需向它提供一些事實(fact)和推論(inference),讓它爲你判斷。編程
聲明式編程包含了函數式編程和邏輯編程。好比lisp haskell prolog,也包含下面示例代碼中使用的js。js是一種多範式語言,既能夠用命令式也能夠用函數式風格編寫代碼。數組
聲明式語言來描述算法很是合適函數式編程
經過上面的簡單對比得知,聲明式編程的抽象程度更高,程序員沒必要糾纏與實現的細節,因此用來描述算法最合適了。函數
以快速排序爲例
A、快速排序以聲明式編程風格實現的例子
function quicksort(list){ if(list.length === 0){ return []; }else{ var n = first(list) //1 , lt = listlet(rest(list),n) //2 , gt = listgt(rest(list),n) //3 // 遞歸 & 合併 return [].concat(quicksort(lt) //4 ,n ,quicksort(gt))//5 } } console.log(quicksort([3,9,2,1,5,4])); // [ 1, 2, 3, 4, 5, 9 ]
代碼自己比較短小,它描述的算法是這樣的
1.取出一個元素做爲參考元素n 。見標註1
2.將這個元素以外的剩餘元素分爲兩部分,小於等於n的元素lt,大於n的元素gt。見標註二、3
3.將lt放n前面,gt放n後面,即按升序排列。可是在這樣排列以前,要遞歸的執行上面兩步,直到碰見空數組。見標註四、5
quicksort依賴下面的工具函數。前兩個工具函數自己也是聲明式風格編寫的。
function listgt(list,n){ return list.filter(function(m){ return m > n; }) } function listlet(list,n){ return list.filter(function(m){ return m <= n; }) } function first(list){ return list[0]; } function rest(list){ return list.slice(1); }
以listgt爲例,聲明式風格的實現爲:
function listgt(list,n){ return list.filter(function(m){ return m > n; }) }
對應的命令式風格的實現爲:
function listgt(list,n){ var ret = []; for(var i=0;i<list.length;i++){ if(list[i]>n){ ret.push(list[i]); } } return ret; }
能夠看出,上面的代碼體現了「命令機器如何作事情,強調細節實現」,包含了一個for循環, 聲明瞭額外的變量i,ret,調用了ret.push方法。感受有不少噪音在裏面。
而前一個listgt實現爲一段聲明,過濾(filter)這個數組,過濾規則爲:這個數組元素m要大於n。過濾就是一種聲明式的描述,「告訴機器作什麼」。過濾功能可能語言自己已經提供給你了,你只須要告訴機器過濾規則就好了。
B、快速排序以命令式風格實現的例子
function swap(items, firstIndex, secondIndex){ var temp = items[firstIndex]; items[firstIndex] = items[secondIndex]; items[secondIndex] = temp; } function partition(items, left, right) { var pivot = items[Math.floor((right + left) / 2)], i = left, j = right; while (i <= j) { while (items[i] < pivot) { i++; } while (items[j] > pivot) { j--; } if (i <= j) { swap(items, i, j); i++; j--; } } return i; } function quickSort(items, left, right) { var index; if (items.length > 1) { left = typeof left != "number" ? 0 : left; right = typeof right != "number" ? items.length - 1 : right; index = partition(items, left, right); if (left < index - 1) { quickSort(items, left, index - 1); } if (index < right) { quickSort(items, index, right); } } return items; } console.log(quickSort([4, 2, 6, 5, 3, 9]));
left和right參數的引入是由於實現算法的細節須要——「命令機器如何作事情,強調細節實現」,用於partition函數劃分數組。
partition函數也有很是多的實現細節。相較而言,不太好閱讀。
參考:
http://blog.zhaojie.me/2010/04/trends-and-future-directions-in-programming-languages-by-anders-2-declarative-programming-and-dsl.html