函數式編程語言

函數式思想java

什麼是函數式編程?c++

百科定義:程序員

 函數式編程是種編程方式,它將電腦運算視爲函數的計算。函數編程語言最重要的基礎是λ演算(lambda calculus),並且λ演算的函數能夠接受函數看成輸入(參數)和輸出(返回值)。數據庫

 我的理解就是咱們的編程是以函數做爲單元來處理各個業務邏輯,函數既能夠當作參數傳來傳去,也能夠做爲返回值,能夠把函數理解一個值到另外一個值得映射關係。編程

 

優點特色性能優化

代碼簡潔、開發快速閉包

 函數式代碼同命令式相比代碼量要少不少,一行頂十行,因此實現一些功能也比較簡潔。框架

功能描述:統計文本或網頁中單詞的頻率TF(term frequency),詞頻在計算網頁質量、信息檢索中是一個重要概念。機器學習

函數式編程思惟是對集合統一處理、統一操做,而命令式編程須要取出來每一個單詞單獨處理,單獨計數,而函數式只須要傳入待處理對象集合、處理規則,咱們不須要關注於具體細節,這樣編程不只僅減小了出現bug的機率並且提升了IT人員開發效率,何樂而不爲呢。編程語言

易於理解,抽象度高

 讓咱們再來看一個在開發中,咱們常常遇到場景,例如咱們有一個List列表,咱們要把user的某個屬性提取出來生成一個新的List。

 

 假設你已經瞭解了函數式語言的語法,你可能會以爲函數式寫法很簡潔,函數式編程並不須要你關注細節實現,咱們在獲取用戶名做爲一個新List時並無對單獨user對象操做,而是是告訴集合對象,咱們要作什麼,思惟重心和關注點從「怎麼作」轉移到了「作什麼」,經過map這個高階函數把集合以及怎麼作的規則傳入,它幫咱們處理集合元素,並返回一個結果集。

 沒有反作用,變量無狀態

 若是一個函數內外有依賴於外部變量或者環境時,經常咱們稱之爲其有反作用,若是咱們僅經過函數簽名不打開內部代碼檢查並不能知道該函數在幹什麼,做爲一個獨立函數咱們指望有明確的輸入和輸出,反作用是bug的發源地,做爲程序員開發者應儘可能少的開發有反作用的函數或方法,反作用也使得方法通用性降低不適合擴展和可重用性。

 函數式編程語言強烈要求使用者編寫沒有反作用的函數,它的函數式數學意義上的函數,給定一個輸入就會有一個輸出,並且每次相同的輸入輸出也確定同樣,函數式中的變量所表明的意義並非內存中的一塊存儲單元,所以多個函數同時操做一個變量或者一個函數調用屢次一個變量都不會改變該變量的值,函數每次對於給定的輸入都是做爲一個新值來處理,就是由於它這種沒有狀態、沒有反作用的理念,很適合大數據計算和處理,它只接受固定輸入既能夠獲得預約計算結果,徹底不依賴於外部環境。

 函數式編程其中的「函數」並非咱們計算機中理解的方法或函數,而是純數學領域函數的概念,看一下百科中對數學函數的定義:

 函數的定義:

 給定一個數集A,對A施加對應法則f,記做f(A),獲得另外一數集B,也就是B=f(A)。

 那麼這個關係式就叫函數關係式,簡稱函數。函數概念含有三個要素:定義域A、值域C和對應法則f。其中核心是對應法則f,它是函數關係的本質特徵。

 命令式程序是基於馮諾依曼計算機結構爲基礎,一條一條的執行操做指令,程序執行效率爲每條命令執行的總和,咱們是面向命令編程,通常咱們使用的語言都是命令式語言。

 好比c c++ java 等等,還有一種編程方式叫作邏輯式編程,代碼風格和命令式同樣,只是在思考過程的時候,更偏重於邏輯思想部分,對於複雜的問題可能會更有優點。

 命令式編程是計算機硬件的抽象,能夠這樣理解,咱們把預先寫好的一條條代碼翻譯成機器語言就是01指令,告訴計算機先執行哪一個命令後執行哪一個命令,最終是去改變了計算機硬件的穩定狀態 1 穩定  0 不穩定 因此,能夠說命令式編程是計算機硬件的抽象。

 函數式編程是對於數學的抽象,理論基礎來源於數學基礎。

 概念分析

閉包

定義:

 一種特殊的函數,綁定了函數內部引用的全部變量,把它引用的東西都放在一個上下文中「包」了起來。

 百科定義:包含兩層含義要執行的代碼塊(自由變量以及自由變量引用的對象)和自由變量的做用域。

 閉包的概念在不少不一樣內容中都有提到,如數據庫原理中函數依賴有閉包、JavaScript也有閉包、好多語言裏面也會提到閉包的概念,它們得意思是否同樣呢?

 答案是同樣的,只是他們的表現形式不同,數據庫中的閉包是描述列是否可達、數據庫範式的依據,把須要的東西放在了「上下文中」包了起來,解釋閉包時先讓咱們來回顧一下前提條件:

 函數式編程以函數做爲一等公民,以函數爲單元完成各類操做,函數是自變量到因變量的一一映射,即一個值到另外一個值得映射。

 接收一個值返回另外一個值,好了前提條件已經有了讓咱們來完成一個函數,計算兩個數的相加操做,以下:

 def plus(senior):    return senior + 100 if  __name__ == '__main__':    result = plus(3)    print result

 

因爲函數只能接收一個參數,該函數只能計算加100,這一種類型加法,想想怎麼才能讓它再接收一個參數不變的狀況下,計算出結果呢,也許你會想到先把值保存起來。

 不過函數式編程是不保存計算中間結果的,即變量是不可變的,咱們能夠把這個函數處理結果傳遞給另外一個函數(一樣接收一個參數),這樣一來便可計算兩個數加法,以下:

 def plus(senior):    def pluaA(second):        return senior + second    return pluaA if  __name__ == '__main__':    pluaA = plus(3)    result = pluaA(2)    print result

 

上面代碼中 plus 便是一個閉包,閉包不只僅是一個函數,從定義能夠看出其包含幾個部分,引用變量、代碼塊、做用域,能夠結合上述代碼加以理解。

 閉包函數裏面的函數雖然有函數名字可是並無意義,只是一個名稱而已從外面不能直接訪問,屬於匿名函數,我的理解它屬於一種特殊的函數以及該函數包含的做用域裏面包含的東西。

 閉包是一種看不見摸不着的東西,所以很差理解,經過閉包能夠將n個函數相互鏈接起來,能夠無限相互之間結果進程映射。

 若是沒有閉包那麼數學中的函數將會是一個個死的函數式子,閉包是函數式編程的靈活、是函數式編程的核心。

 把代碼綁定到閉包後,能夠推遲到適當的時機再執行閉包,是一種對行爲的建模手段,讓咱們把代碼和上下文同時封裝在單一結構,也就是閉包裏面,之後執行。

 高階函數

高階函數從字面上面理解除了普通函數功能仍是高級內容,便可以把函數做爲參數或者返回值的函數,從這個角度來講加強了函數處理能力,書上定義爲能夠接收函數爲參數或者返回一個函數做爲參數的函數。

 你們思考一下,高階函數爲何能夠這麼設計,閉包在裏面起到了什麼做用?

 匿名函數

匿名函數即lambda表達式函數,常常做爲函數參數或者生成表達式的場景中,閉包中裏面的函數能夠當作是匿名函數來理解,上面計算兩個數的加法還能夠改成這樣:

 def plus2(senior):    return lambda second:senior+second if  __name__ == '__main__':    pluaA2 = plus2(3)    result = pluaA2(2)    print result

 這兩種寫法意思和做用是同樣的,其實上面的PluaA也是匿名函數,只不過這樣寫會易於閱讀和理解,匿名函數經常使用在比較簡單的參數表達式中,使得代碼簡化、簡潔,可是不要濫用匿名函數,若是代碼中處處是匿名函數那麼看起來會很很差理解。

 柯里化

通俗的理解是將函數的參數變爲一個參數的形式,函數式編程提倡柯里化編程,儘可能編寫一個參數的函數,優化方便,簡化代碼。

 語法糖

指程序的可閱讀性更高、能夠給咱們帶來方便,更簡潔的寫法,提升開發編碼效率。

 某種語言中添加了某種語法,這種語法對功能沒有影響,但能夠提升可閱讀性、間接性等,則稱這種語法爲該語言的語法糖

 性能優化

緩求值

 是函數式編程語言的一種特性,這個特性也比較好理解,儘量的推遲函數或表達式的計算過程,等到真正用到的時候才加載數據,類俗語hibernate框架中的懶加載,利用緩求值的方式來使用映射,能夠產生更高效率的代碼。

 尾遞歸、尾調用

 尾調用是在函數的尾部,調用另外一個函數,由於函數是語言沒有循環,遞歸很重要,對於遞歸須要來不斷優化,通常採用尾調用或尾遞歸來優化。

 顧名思義,尾遞歸就是從最後開始計算, 每遞歸一次就算出相應的結果, 也就是說, 函數調用出如今調用者函數的尾部 ,尾遞歸就是把當前的運算結果(或路徑)放在參數裏傳給下層函數和普通遞歸區別在於內存佔用。

 總結

函數式編程其特性很是適合於大數據處理、科學計算、數據統計等業務,隨着人工智能、機器學習、深度學習的流行正在變得重要起來。

相關文章
相關標籤/搜索