1. 程式人生 > >函數語言程式設計概述

函數語言程式設計概述

函數語言程式設計概述

“函數語言程式設計”, 又稱泛函程式設計, 是一種”程式設計正規化”(programming paradigm),也就是如何編寫程式的方法論。它的基礎是 λ 演算(lambda calculus)。λ演算可以接受函式當作輸入(引數)和輸出(返回值)。

和指令式程式設計相比,函數語言程式設計的思維方式更加註重函式的計算。它的主要思想是把問題的解決方案寫成一系列巢狀的函式呼叫。

函數語言程式設計中最古老的例子莫過於1958年被創造出來的Lisp了。Lisp由約翰·麥卡錫(John McCarthy,1927-2011)在1958年基於λ演算所創造,採用抽象資料列表與遞迴作符號演算來衍生人工智慧。較現代的例子包括Haskell、ML、Erlang等。現代的程式語言對函數語言程式設計都做了不同程度的支援,例如:JavaScript, Coffee Script,PHP,Perl,Python, Ruby, C# , Java 等等(這將是一個不斷增長的列表)。

函數語言程式設計思想是一個非常古老的思想。簡述如下:

  • 我們就從1900 年 David Hilbert 的第 10 問題(能否通過有限步驟來判定不定方程是否存在有理整數解?) 開始說起吧。

  • 1920,Schönfinkel,組合子邏輯(combinatory logic)。直到 Curry Haskell 1927 在普林斯頓大學當講師時重新發現了 Moses Schönfinkel 關於組合子邏輯的成果。Moses Schönfinkel的成果預言了很多 Curry 在做的研究,於是他就跑去哥廷根大學與熟悉Moses Schönfinkel工作的Heinrich Behmann、Paul Bernays兩人一起工作,並於 1930 年以一篇組合子邏輯的論文拿到了博士學位。Curry Brooks Haskell 整個職業生涯都在研究組合子,實際開創了這個研究領域,λ演算中用單引數函式來表示多個引數函式的方法被稱為 Currying (柯里化),雖然 Curry 同學多次指出這個其實是 Schönfinkel 已經搞出來的,不過其他人都是因為他用了才知道,所以這名字就這定下來了;並且有三門程式語言以他的名字命名,分別是:Curry, Brooks, Haskell。Curry 在 1928 開始開發型別系統,他搞的是基於組合子的 polymorphic,Church 則建立了基於函式的簡單型別系統。

  • 1929, 哥德爾(Kurt Gödel )完備性定理。Gödel 首先證明了一個形式系統中的所有公式都可以表示為自然數,並可以從一自然數反過來得出相應的公式。這對於今天的程式設計師都來說,數字編碼、程式即資料計算機原理最核心、最基本的常識,在那個時代卻腦洞大開的創見。

  • 1933,λ 演算。 Church 在 1933 年搞出來一套以純λ演算為基礎的邏輯,以期對數學進行形式化描述。 λ 演算和遞迴函式理論就是函數語言程式設計的基礎。

  • 1936,確定性問題(decision problem,德文 Entscheidungsproblem (發音 [ɛntˈʃaɪ̯dʊŋspʁoˌbleːm])。 Alan Turing 和 Alonzo Church,兩人在同在1936年獨立給出了否定答案。

1935-1936這個時間段上,我們有了三個有效計算模型:通用圖靈機、通用遞迴函式、λ可定義。Rosser 1939 年正式確認這三個模型是等效的。

  • 1953-1957,FORTRAN (FORmula TRANslating ),John Backus。1952 年 Halcombe Laning 提出了直接輸入數學公式的設想,並製作了 GEORGE編譯器演示該想法。受這個想法啟發,1953 年 IBM 的 John Backus 團隊給 IBM 704 主機研發數學公式翻譯系統。第一個 FORTRAN (FORmula TRANslating 的縮寫)編譯器 1957.4 正式發行。FORTRAN 程式的程式碼行數比彙編少20倍。FORTRAN 的成功,讓很多人認識到直接把代數公式輸入進電腦是可行的,並開始渴望能用某種形式語言直接把自己的研究內容輸入到電腦裡進行運算。John Backus 在1970年代搞了 FP 語言,1977 年發表。雖然這門語言並不是最早的函數語言程式設計語言,但他是 Functional Programming 這個詞兒的創造者, 1977 年他的圖靈獎演講題為[“Can Programming Be Liberated From the von Neumann Style? A Functional Style and its Algebra of Programs”]

  • 1956, LISP, John McCarthy。John McCarthy 1956年在 Dartmouth一臺 IBM 704 上搞人工智慧研究時,就想到要一個代數列表處理(algebraic list processing)語言。他的專案需要用某種形式語言來編寫語句,以記錄關於世界的資訊,而他感覺列表結構這種形式挺合適,既方便編寫,也方便推演。於是就創造了LISP。正因為是在 IBM 704 上開搞的,所以 LISP 的表處理函式才會有奇葩的名字: car/cdr 什麼的。其實是取 IBM704 機器字的不同部分,c=content of,r=register number, a=address part, d=decrement part 。

 

面向函式程式設計(FOP)

在FP中,一切皆是函式。

函數語言程式設計(FP)是關於不變性和函式組合的一種程式設計正規化。

函數語言程式設計語言實現重用的思路很不一樣。函式式語言提倡在有限的幾種關鍵資料結構(如list、set、map)上 , 運用函式的組合 ( 高階函式) 操作,自底向上地來構建世界。

當然,我們在工程實踐中,是不能極端地追求純函式式的程式設計的。一個簡單的原因就是:效能和效率。例如:對於有狀態的操作,命令式操作通常會比宣告式操作更有效率。純函數語言程式設計是解決某些問題的偉大工具,但是在另外的一些問題場景中,並不適用。因為副作用總是真實存在。

OOP喜歡自頂向下架構層層分解(解構),FP喜歡自底向上層層組合(複合)。 而實際上,程式設計的本質就是次化分解與複合的過程。通過這樣的過程,創造一個美妙的邏輯之塔世界。

我們經常說一些程式碼片段是優雅的或美觀的,實際上意味著它們更容易被人類有限的思維所處理。

對於程式的複合而言,好的程式碼是它的表面積要比體積增長的慢。

程式碼塊的“表面積”是我們複合程式碼塊時所需要的資訊(介面API協議定義)。程式碼塊的“體積”就是介面內部的實現邏輯(API內部的實現程式碼)。

在OOP中,一個理想的物件應該是隻暴露它的抽象介面(純表面, 無體積),其方法則扮演箭頭的角色。如果為了理解一個物件如何與其他物件進行復合,當你發現不得不深入挖掘物件的實現之時,此時你所用的程式設計正規化的原本優勢就蕩然無存了。

FP通過函式組合來構造其邏輯系統。FP傾向於把軟體分解為其需要執行的行為或操作,而且通常採用自底向上的方法。函數語言程式設計也提供了非常強大的對事物進行抽象和組合的能力。

在FP裡面,函式是“一類公民”(first-class)。它們可以像1, 2, “hello”,true,物件…… 之類的“值”一樣,在任意位置誕生,通過變數,引數和資料結構傳遞到其它地方,可以在任何位置被呼叫。

而在OOP中,很多所謂面向物件設計模式(design pattern),都是因為面嚮物件語言沒有first-class function(對應的是多型性),所以導致了每個函式必須被包在一個物件裡面(受約束的函式指標)才能傳遞到其它地方。

 

函數語言程式設計基本特性

在經常被引用的論文 “Why Functional Programming Matters” 中,作者 John Hughes 說明了模組化是成功程式設計的關鍵,而函式程式設計可以極大地改進模組化。

在函式程式設計中,我們有一個內建的框架來開發更小的、更簡單的和更一般化的模組, 然後將它們組合在一起。

函式程式設計的一些基本特點包括:

  • 函式是”第一等公民”。
  • 閉包(Closure)和高階函式(Higher Order Function)。
  • Lambda演算與函式柯里化(Currying)。
  • 懶惰計算(lazy evaluation)。
  • 使用遞迴作為控制流程的機制。
  • 引用透明性。
  • 沒有副作用。

 

參考出處:https://blog.csdn.net/axi295309066/article/details/78040241