函數式編程(文章質量不高)

編程範式
函數式編程是一種編程範式,咱們常見的編程範式有命令式編程(Imperative programming)函數式編程邏輯式編程,常見的面向對象編程是也是一種命令式編程。html

命令式編程是面向計算機硬件的抽象,有變量(對應着存儲單元),賦值語句(獲取,存儲指令),表達式(內存引用和算術運算)和控制語句(跳轉指令),一句話,命令式程序就是一個馮諾依曼機指令序列express

而函數式編程是面向數學的抽象,將計算描述爲一種表達式求值,一句話,函數式程序就是一個表達式編程

以上內容摘自https://www.zhihu.com/question/28292740/answer/40336090,難懂!併發

下面來自阮一峯 函數式編程處探ide

1、定義模塊化

簡單說,「函數式編程」是一種「編程範式」(programming paradigm),也就是如何編寫程序的方法論。函數式編程

它屬於「結構化編程」的一種,主要思想是把運算過程儘可能攜程一些列嵌套的函數調用。舉例來講,如今有這樣一個數學表達式:函數

( 1 + 2 ) * 3 - 4

傳統的過程式編程,可能這樣寫單元測試

var a = 1 + 2;

var b = a * 3;

var c = b - 4;

函數式編程要求使用函數,咱們能夠把運算過程定義爲不一樣的函數,而後寫出下面這樣:測試

var result = subtract(multiply(add(1, 2), 3), 4);

這就是函數式編程。

2、特色

函數式編程有五個鮮明的特色。

一、函數是「第一等公民」

所謂「第一等公民」(first class),指的是函數與其餘數據類型同樣,處於平等地位,能夠賦值給其餘變量,也能夠做爲參數,傳入另外一個函數,或者做爲別的函數的返回值。

舉例來講,下面代碼中的print變量,能夠做爲另外一個函數的參數。

var print = function( i ) { console.log(i); };

[1, 2, 3].forEach(print);

二、只用「表達式」,不用「語句」

「表達式」( expression )是一個單純的運算過程,老是有返回值;「語句」( statement )是執行某種操做,沒有返回值。函數式編程要求,只使用表達式,不使用語句。也就是說,每一步都是單純的運算,並且都有返回值。

緣由是函數式編程的開發動機,一開始就是爲了處理運算( computation ),不考慮系統的讀寫( I/O )。「語句」屬於對系統的讀寫操做,因此就被排斥在外。

固然,實際應用中,不作I/O是不可能的。所以,編程過程當中,函數式編程只要求把I/O限制到最小,不要有沒必要要的讀寫行爲,保持計算過程的單純性。

三、沒有「反作用」

所謂「反作用」( side effect ),指的是函數內部與外部互動( 最典型的狀況,就是修改全局變量的值,產生運算意外的其餘結果 )。

函數式編程敲掉沒有「反作用」,意味着函數要保持獨立,全部功能就是返回一個新的值,沒有其餘行爲,尤爲是不得修改外部變量的值。

四、不修改狀態

上一點已經提到,函數式編程知識返回新的值 ,不修改系統變量。所以,不修改變量,也是它的一個重要特色。

在其餘類型的語言中,變量每每用來保存「狀態」( state )。不修改變量,意味着狀態不能保存在變量中。函數式編程使用參數保存狀態,最好的例子就是遞歸。下面的代碼是一個將字符串逆序排列的函數,它演示了不一樣的參數如何決定了運算所處的「狀態」。

function reverse(string) {
    if (string.length == 0) {
        return string;
    } else {
        return reverse(string.substring(1, string.length) + string.substring(0, 1));
    }
}

因爲使用了遞歸,函數式語言的運行速度比較慢,這是它長期不能在業界推廣的主要緣由。

五、引用透明

引用透明( Referential transparency ),值的是函數在運行不依賴於外部變量或「狀態」,只依賴於輸入的參數,任什麼時候候只要參數相同,引用函數所獲得的返回值老是相同的。

有了前面的第三點和第四點,這點很顯然的,求他類型的語言,函數的返回值每每與系統的狀態有關,不一樣的狀態之下,返回值是不同的。這就叫「引用不透明」,很不利於觀察和理解程序的行爲。

3、意義

函數式編程到底有什麼好處,爲何會變得愈來愈流行?

一、代碼簡介,開發快速。

函數式編程大量使用函數,減小了代碼的重複,所以程序比較短,開發速度較快。

二、接近天然語言,易於理解

函數式編程的自由度很高,能夠寫出很接近天然語言的代碼。

前文曾經將表達式

( 1 + 2 ) * 3 - 4

寫成函數式語言:

subtract(multiply(add(1, 2), 3), 4);

對它進行變形,不可貴到另外一種寫法:

add(1, 2).multiply(3).substract(4)

這基本就是天然語言表達了。再看下面的代碼,你們應該一眼就能明白它的意思吧:

merge([1, 2], [3, 4]).sort().search('2')

所以,函數式編程的代碼更容易理解。

三、更方便的代碼管理

函數式編程不依賴、也不會改變外界的狀態,只要給定輸入參數,返回的結果一定相同。所以每個函數均可以被看作獨立單元,頗有利於進行單元測試( unit testing )和除錯( debugging ),一級模塊化組合。

四、易於「併發編程」

函數式編程不須要考慮「死鎖」( deadlock ),由於它不修改變量,因此根本不存在「鎖」線程的問題。沒必要擔憂一個線程的數據,被另外一個線程修改,因此能夠很放心地把工做分攤到多個線程,部署「併發編程」( concurrency )。

請看下面的代碼:

var s1 = Op1();
var s2 = Op2();
var s3 = concat(s1, s2);

因爲s1和s2互不干擾,不會修改變量,誰先執行是無所謂的,因此能夠放心地增長線程,把他們分配在兩個線程上完成。其餘類型的語言就作不到這一點,由於s1可能會修改系統狀態,而s2可能會用到這些狀態,因此必須保證s2在s1以後進行,天然也就不能部署到其餘線程上了。

多喝CPU是未來的潮流,因此函數式編程的這個特性很是重要。

五、代碼的熱升級

函數式編程沒有反作用,只要保證接口不變,內部實現是外部無關的。因此,能夠在運行狀態下直接升級代碼,不須要重啓,也不須要停機。

(完)

相關文章
相關標籤/搜索