函數柯里化和偏函數應用

什麼是函數柯里化(Currying)


維基百科中的定義:bash

在計算機科學中,柯里化(英語:Currying),又譯爲卡瑞化或加里化,是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,而且返回接受餘下的參數並且返回結果的新函數的技術。閉包

換句話說就是把一個有n個參數的函數轉換成n個嵌套的函數,每一個函數只接受一個參數,並返回一個新函數。也就是把f(a,b,c)轉化爲f(a)(b)(c)函數

 

例子


例如一個函數接受a, b, c三個參數,返回它們的乘積:ui

function multiply(a, b, c) {
    return a * b * c;
}
複製代碼

運行此函數,咱們在參數中依次傳入1,2,3,返回6。this

multiply(1,2,3); // 6

複製代碼

讓咱們看一下柯里化以後的樣子:spa

function multiply(a) {
    return (b) => {
        return (c) => {
            return a * b * c
        }
    }
}
multiply(1)(2)(3) // 6
複製代碼

咱們把multiply(1,2,3)變成了multiply(1)(2)(3)的形式。經過把一個多參函數轉換成一系列嵌套的函數,每一個函數依次接受一個參數,這就是函數柯里化。code

或者換一種寫法能夠更容易理解:ip

function multiply(a) {
    return (b) => {
        return (c) => {
            return a * b * c
        }
    }
}
const mul1 = multiply(1);
const mul2 = mul1(2);
const result = mul2(3);  // 6
複製代碼

multiply函數接受一個a參數,咱們傳入1。mult1等於multiply(1)就等於it

(b) => {
    return (c) => {
        return a * b * c
    }
}
複製代碼

而且接受一個參數b。以此類推,mul1(2)傳入2,而後賦值給mult2等於io

(c) => {
    return a * b * c
}
複製代碼

最後mul2(3)返回a * b * c。因爲閉包的特性會保存以前傳入的值1和2,最後得出6。

 

函數柯里化的應用


  • 柯里化函數避免咱們重複傳參,實現複用

假設咱們有一個函數用來計算三個物體的體積。

function volume(l, w, h) {
    return l * w * h;
}
volume(200,30,100) // 2003000
volume(32,45,100); //144000
volume(2322,232,100) // 53870400
複製代碼

從上面代碼能夠看出,若是每一個物體的高度都是100,咱們須要重複傳三次。 若是使用柯里化函數能夠避免:

function volume(h) {
    return (w) => {
        return (l) => {
            return l * w * h
        }
    }
}

//固定高度
const itemHeight = volume(100);

//計算其餘不一樣狀況
itemHeight(30)(200); 
itemHeight(45)(32); 
itemHeight(232)(2322); 
複製代碼
  • 函數的合成

合成兩個函數的簡單代碼以下:

var compose = function(f,g) {
  return function(x) {
    return f(g(x));
  };
};
複製代碼

f(x)g(x)合成爲f(g(x)),有一個隱藏的前提,就是f和g都只能接受一個參數, 其中就運用了函數柯里化。

 

什麼是偏函數應用(Partial Application)


Partial Application(偏函數應用)很容易和函數柯里化混淆,它是指使用一個函數並將其應用一個或多個參數,但不是所有參數,在這個過程當中建立一個新函數,這個函數用於接受剩餘的參數。這段話很不容易理解,具體看下面的例子:

 

例子


function multiply(a,b,c){
    return a * b * c;
}
//生產偏函數的工廠
function partial(fn,a){
    return function(b,c){
        return fn(a,b,c);
    }
}

//變量parMulti接受返回的新函數
var parMulti = partial(multiply,1);

//在調用的時候傳入剩餘的參數
parMulti(2,3); // 6
複製代碼
  1. partial函數能夠幫咱們生成一個偏函數。
  2. 調用partial函數生成一個偏函數並賦值給parMulti,其中預設一個值1
  3. parMulti接受剩餘參數2,3結合前面預設的1得出最終結果。

 

偏函數的應用


例如bind函數可讓咱們傳入一個或多個想要預設的參數,以後返回一個新函數,並擁有指定的this值和預設參數。當綁定函數被調用時,這些參數會被插入到目標函數的參數列表的開始位置,傳遞給綁定函數的參數會跟在它們後面。

function addition(x, y) {
   return x + y;
}
const plus5 = addition.bind(null, 5)
plus5(10) // output -> 15
plus5(20) // output -> 25
複製代碼

咱們預先傳入了參數5,並返回了一個新函數賦值給plus5,此函數能夠接受剩餘的參數。調用plus5傳入剩餘參數10得出最終結果15,如傳入20得出25。偏函數經過設定預設值,幫咱們實現代碼上的複用。

 

總結


柯里化和偏函數都是用於將多個參數函數,轉化爲接受更少參數函數的方法。傳入部分參數後,處於中間狀態的函數能夠做爲固定值進行復用。可是其中不一樣之處在於:

  • 柯里化是將函數轉化爲多個嵌套的一元函數,也就是每一個函數只接受一個參數。
  • 偏函數能夠接受不僅一個參數,它被固定了部分參數做爲預設,並能夠接受剩餘的參數。
相關文章
相關標籤/搜索