面向函數范式編程(Functional programming)

  函數編程(簡稱FP)不只代指Haskell Scala等之類的語言,還表示一種編程思維,軟件思考方式,也稱面向函數編程。 編程的本質是組合,組合的本質是范疇Category,而范疇是函數的組合。

  首先,什么是函數式編程,這并沒有唯一定義,它只是廣泛聚合了一些編程風格的特性,我們可以將它與面向對象編程OOP進行對比, 兩者區別是,OOP主要聚焦于數據的區別,而FP則注重數據結構的一致性。OOP最大優點是多態性和封裝;而FP優勢是不變性及其聲明性風格,兩者其實是正交,可互補的,可在同一程序中共存。

面向對象:

  1. 數據和對數據的操作緊緊耦合
  2. .對象隱藏它們操作的實現細節,其他對象調用這些操作只需要通過接口。
  3. .核心抽象模型是數據自己
  4. 核心活動是組合新對象和拓展已經存在的對象,這是通過加入新的方法實現的。

函數編程:

  1. 數據與函數是松耦合的
  2. 函數隱藏了它們的實現,語言的抽象是函數,以及將函數組合起來表達。
  3. 核心抽象模型是函數,不是數據結構
  4. 核心活動是編寫新的函數。
  5. 變量缺省是不變的,減少可變性變量的使用,并發性好

  那么OOP和FP在業務領域是否有勝者呢? 我們大部分業務邏輯是這樣寫:


SELECT orders.order_id, orders.order_date, suppliers.supplier_name
  FROM suppliers
  RIGHT OUTER JOIN orders
  ON suppliers.supplier_id = orders.supplier_id
  WHERE orders.order_status = 'INCOMPLETE'
  ORDER BY orders.order_date DESC;

  SQL是非常類似FP,它能滲透到業務中,它使用一致的數據結構(數據表結構Schema),一些基本函數能組合成很多查詢語句,它是declarative聲明式的, 也就是說,寫出的SQL是告訴數據庫我需要什么,數據庫就為你返回,而不必指定數據庫如何具體去查詢。

  聲明式編程和命令式編程區別? FP的主要特點是它們描述它們要"什么",而不是如何實現。而OO在其方法中,還是使用大部分命令式技術。 下面是命令式技術代碼:

var sumOfSquares = function(list) {
  var result = 0;
  for (var i = 0; i < list.length; i++) {
    result += square(list[i]);
  }
  return result;
};

console.log(sumOfSquares([2, 3, 5]));

函數編程代碼如下:
var sumOfSquares = pipe(map(square), reduce(add, 0));
console.log(sumOfSquares([2, 3, 5]));

  函數風格的編程特點:

  1. 第一等公民是函數
  2. 帶有閉包的Lambdas/Anonymous函數
  3. 不變性,大部分無態處理,沒有狀態和變量
  4. 高并發
  5. 無副作用的調用
  6. 通過tail call實現遞歸的性能優化。
  7. 模式匹配(Haskell, Erlang)
  8. 懶賦值(Miranda, Haskell)
  9. Homoiconicity(類似LISP)

  如果說OOP還有很多人可能受靜態數據思路影響,那么FP 帶來完全是動態事件,FP讓我們直接用動詞思考,用方法函數解決問題,比如兩個帳號之間的轉帳,按照DDD等靜態領域建模思維,轉帳這個功能是放在帳號這個實體類中,還是做一個服務呢?在OOP語言中,我們實現功能總是使用服務Service這樣一個概念替代,而且強調無態服務,無態服務實際就是一個只有方法函數沒有屬性的空架子“類”而已。 2007年的Adam Heroku一篇博文中寫道:銀行賬戶之間轉帳的老式做法是使用數據庫事務,這種做法比較剛性,正確做法是將轉帳事件存儲起來,如果你是一個面向函數范式的思維者覺得這樣做就很正常。---來自" NOSQL存儲的基于事件的事務實現 " 。

  有很多人將FP歸結于數學思維,實際上這只看到其表面,沒有看到數學語言這個背后的形式邏輯,編程語言作為和數學同等形式語言,他們的核心基礎都是分析哲學的形式邏輯,過去的面向對象很多設計原則也來源于形式邏輯,見:蒯因與引用透明 。  

  面向對象和面向函數一直在爭論,實際上純粹的OOP和純粹的FP都是極端的,對于OOP來講:存在的并一定都是對象,函數就不是對象;對于FP來說:存在的并不總是純粹的,副作用總是真實存在。總之,面向對象側重于分解,函數編程側重于組合。

 

文章

類型系統和邏輯

函數式編程模式:單位元(幺元)

函數式編程模式:半群

范疇category:組合的本質

什么是Monoid ?

什么是Monad?

為什么需要Monad??

面向對象與函數編程的比較

OOP和FP錯在哪里?

為什么組合好于繼承??

什么是流式思維?

Reactive設計語言與范式

蒯因與引用透明

為什么我再也不使用MVC框架了?

微服務的最終一致性與事件流

一張圖解說Map/filter/reduce

從CRUD編程切換到事件溯源和區塊鏈編程

一篇有關函數式編程的形象生動教程

Java8

Closure Lambda和Monad

分分鐘學會Java8的Lambda

Java 8十個lambda表達式案例

Java8教程

使用Java8的Lambda實現的一個簡單案例

使用Java8的Lambda實現Monda

使用Java8的Lambda實現模板模式

使用Java8的Lambda實現策略模式

Java8的Lambda和排序

用Java 8 lambda優化JDBC

使用Java8的Lambda簡化ReadWriteLock

Java 8的Lambda表達式的陰暗面

用monad替代嵌套回調

更多Java8專題

 

其他語言

HASKELL入門起步

Scala入門之函數編程

Scala入門之基本概念

更多Scala專題

Javascript閉包是什么?

Scala中文教程和手冊

蘋果Swift語言中文簡明教程

Javascript的函數式編程術語解釋

 

參考

Python語言教程手冊

Reactive專題

面向函數編程系列專題

EventSourcing  

形式邏輯專題

Node.js專題

 

一级黄色录像影片 夫妻性生活影片 免费在线观看 一级a做爰片