從函數式編程到Ramda函數庫(一)

  函數式編程是種編程方式,它將電腦運算視爲函數的計算。函數編程語言最重要的基礎是λ演算(lambda calculus),並且λ演算的函數能夠接受函數看成輸入(參數)和輸出(返回值)。和指令式編程相比,函數式編程強調函數的計算比指令的執行重要。和過程化編程相比,函數式編程裏函數的計算可隨時調用。編程

  最近一直在研究函數式編程,從函數式編程中彷彿看到了js規範化的影子。你們都知道js是一門很靈活的編程語言,而這種靈活性在代碼量的累積下會產生質量和可控性的問題。初學js的朋友大多都是結果導向,寫的代碼剛剛夠用現有的項目,很難修改與擴展代碼,並且不規範的代碼經常讓隊友甚至是本身頭疼。而函數式編程卻能改變這樣的現狀。數組

  再說函數式編程以前按照慣例要說一些相關的知識。緩存

1.什麼是純函數?

  純函數顧名思義就是很純的函數,你們都喜歡純粹的事物,那什麼樣的函數才配稱做純函數呢?
  簡單地說,純函數就是傳入相同的參數能夠返回相同的值的函數,也就是說返回的結果只依賴於傳遞的參數,而和環境沒有關係。相似於咱們數學中的函數的概念。dom

Array.prototype.map()
Array.prototype.slice()
String.prototype.toUpperCase()

  像上面這樣的函數就是純函數編程語言

Array.prototype.sort()
Math.random()

  像上面這樣的函數就不是純函數了
  純函數有不少優秀的性質讓咱們喜歡,ide

1.純潔性

  她既不會被環境改變也不會改變環境,結果只依賴傳入值。那麼這就方便咱們對函數進行緩存。下面以求x的平方爲例(這裏用到了ramda函數庫,沒接觸也不要緊,這裏只是講概念,以後咱們會說起這個函數庫)函數式編程

let square = R.memoizeWith(R.identity, x => x * x);
square(3); // => 9 第一次會調用原始方法並將參數和結果以key-value的形式存儲。
square(3); // => 9 這裏是調用緩存
square(3); // => 9 這裏也是調用緩存

2.易測試性

  因爲純函數執行不須要環境,因此進行測試時咱們只須要面對函數自己測試就能夠了。這讓函數測試變得很是簡單函數

3.透明性

  若是一段代碼能夠替換成它執行所得的結果,並且是在不改變整個程序行爲的前提下替換的,那麼咱們就說這段代碼是引用透明的。因爲純函數老是可以根據相同的輸入返回相同的輸出,因此它們就可以保證老是返回同一個結果,這也就保證了引用透明性。測試

2.什麼是柯里化?

  函數柯里化(curry)的定義很簡單:傳遞給函數一部分參數來調用它,讓它返回一個函數去處理剩下的參數。下面咱們對比一下柯里化以前的函數和柯里化的函數。spa

let add = (x, y, z) => x + y + z;
add(1,2,3) // => 6;
let add = (x, y, z) => {
  return z => {
    return y => {
      return x + y + z;
    }
  }
}
add(1)(2)(3) // => 6;

  後者就是柯里化的函數,它利用了函數的記憶性記住了每次傳你進去的參數並返回了可繼續執行的函數。是否是感受發現了新大陸?

3.什麼是函數組合

  函數組合(compose)就是把多個純函數組合起來解決函數嵌套問題。下面咱們來看兩個例子

let compose = (f, g, h) => x => f(g(h(x)));
let add = x => x + 4;
let mul = x => x * 2;
let mis = x => x - 1;
compose(add, mul, mis)(1) // => 3
let compose = (f, g, h) => x => f(g(h(x)));
let getFirst = arr => arr[0];
let getUpperCase = str => str.toUpperCase();
let getReverse = arr => arr.reverse();
compose(getUpperCase, getFirst, getReverse)(['v', 'a', 'd', 'i', 'm']); // => 'M'

  由於純函數的純潔性,咱們能夠把多個函數組合起來,注意必定是純函數。

4.什麼是point-free

point-free簡單地說就是無需使用所要處理的值,只關注運算過程。能夠用公式 fn = R.pipe(f1, f2, f3);表示,也就是說若是事先定義了函數f1,f2,f3就能夠推算出函數fn,所以無需使用參數形式,下面咱們來對比一下兩種形式。

let noPointFree = word => word.toUpperCase().split('-');
let pointFree = compose(split('-'),toUpperCase);

  pointfree 模式可以幫助咱們減小沒必要要(中間變量)的命名,讓代碼保持簡潔和通用。

  關於函數式編程先講一下基礎的知識,下一節我來說一下js函數式編程優秀的函數庫----Ramda函數庫。

 

原創博客:轉載請註明從函數式編程到Ramda函數庫(一)

相關文章
相關標籤/搜索