成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

函數(shù)式編程 - 組合compose

zhangrxiang / 1787人閱讀

摘要:函數(shù)式編程中有一個(gè)比較重要的概念就是函數(shù)組合組合多個(gè)函數(shù),同時(shí)返回一個(gè)新的函數(shù)。深入理解認(rèn)識函數(shù)式編程里面跟類似的方法,就是。主要作用也是組合多個(gè)函數(shù),稱之為流,肯定得按照正常方法,從左往右調(diào)用函數(shù),與調(diào)用方法相反。

函數(shù)式編程中有一個(gè)比較重要的概念就是函數(shù)組合(compose),組合多個(gè)函數(shù),同時(shí)返回一個(gè)新的函數(shù)。調(diào)用時(shí),組合函數(shù)按順序從右向左執(zhí)行。右邊函數(shù)調(diào)用后,返回的結(jié)果,作為左邊函數(shù)的參數(shù)傳入,嚴(yán)格保證了執(zhí)行順序,這也是compose 主要特點(diǎn)。

入門簡介 組合兩個(gè)函數(shù)

compose 非常簡單,通過下面示例代碼,就非常清楚

function compose (f, g) {
    return function(x) {
        return f(g(x));
    }
}

var arr = [1, 2, 3],
    reverse = function(x){ return x.reverse()},
    getFirst = function(x) {return x[0]},
    compseFunc = compose(getFirst, reverse);
    
compseFunc(arr);   // 3

參數(shù)在函數(shù)間就好像通過‘管道’傳輸一樣,最右邊的函數(shù)接收外界參數(shù),返回結(jié)果傳給左邊的函數(shù),最后輸出結(jié)果。

組合任意個(gè)函數(shù)

上面組合了兩個(gè)函數(shù)的compose,也讓我們了解了組合的特點(diǎn),接著我們看看如何組合更多的函數(shù),因?yàn)樵趯?shí)際應(yīng)用中,不會(huì)像入門介紹的代碼那么簡單。

主要注意幾個(gè)關(guān)鍵點(diǎn):

利用arguments的長度得到所有組合函數(shù)的個(gè)數(shù)

reduce 遍歷執(zhí)行所有函數(shù)。

    var compose = function() {
      var args = Array.prototype.slice.call(arguments);
      
      return function(x) {
       if (args.length >= 2) {
       
          return args.reverse().reduce((p, c) => {
            return p = c(p)
         }, x)
         
       } else {
           return args[1] && args[1](x);
       }
      }
    }
   
    // 利用上面示例 測試一下。
    var arr = [1, 2, 3],
    reverse = function(x){ return x.reverse()},
    getFirst = function(x) {return x[0]},
    trace = function(x) {  console.log("執(zhí)行結(jié)果:", x); return x}
    
    
    compseFunc = compose(trace, getFirst, trace, reverse);
    
compseFunc(arr);   
 // 執(zhí)行結(jié)果: (3)?[3, 2, 1]
 // 執(zhí)行結(jié)果: 3
 // 3

如此實(shí)現(xiàn),基本沒什么問題,變量arr 在管道中傳入后,經(jīng)過各種操作,最后返回了結(jié)果。

深入理解 認(rèn)識pipe

函數(shù)式編程(FP)里面跟compose類似的方法,就是pipe。
pipe,主要作用也是組合多個(gè)函數(shù),稱之為"流", 肯定得按照正常方法,從左往右調(diào)用函數(shù),與compose 調(diào)用方法相反。

ES6 實(shí)現(xiàn)Compose function

先看下compose 最基礎(chǔ)的兩參數(shù)版本,

const compose = (f1, f2) => value => f1(f2(value));

利用箭頭函數(shù),非常直接的表明兩個(gè)函數(shù)嵌套執(zhí)行的關(guān)系,

接著看多層嵌套。

    (f1, f2, f3...) => value => f1(f2(f3));

抽象出來表示:

     () => () => result;

先提出這些基礎(chǔ)的組合方式,對我們后面理解高級es6方法實(shí)現(xiàn)compose有很大幫助。

實(shí)現(xiàn)pipe

前面提到pipe 是反向的compose,pipe正向調(diào)用也導(dǎo)致它實(shí)現(xiàn)起來更容易。

pipe = (...fns) => x => fns.reduce((v, f) => f(v), x)
    

一行代碼就實(shí)現(xiàn)了pipe, 套用上面抽象出來的表達(dá)式,reduce剛好正向遍歷所有函數(shù), 參數(shù)x作為傳遞給函數(shù)的初始值, 后面每次f(v)執(zhí)行的結(jié)果,作為下一次f(v)調(diào)用的參數(shù)v,完成了函數(shù)組合調(diào)用。

或者,可以把函數(shù)組合中,第一個(gè)函數(shù)獲取參數(shù)后,得到的結(jié)果,最為reduce遍歷的初始值。

pipe = (fn,...fns) => (x) => fns.reduce( (v, f) => f(v), fn(x));

利用es6提供的rest 參數(shù) ,用于獲取函數(shù)的多余參數(shù).提取出第一個(gè)函數(shù)fn,多余函數(shù)參數(shù)放到fns中,fns可以看成是數(shù)組,也不用像arguments那種事先通過Array.prototype.slice.call轉(zhuǎn)為數(shù)組,arguments對性能損耗也可以避免。 fn(x) 第一個(gè)函數(shù)執(zhí)行結(jié)果作為reduce 初始值。

實(shí)現(xiàn)compose

pipe 部分,利用reduce實(shí)現(xiàn),反過來看,compose就可以利用reduceRight

compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);

利用遞歸

compose = (fn, ...fns) => fns.length === 0 ? fn: (...args) => fn(compose(...fns)(...args))

遞歸代碼,首先看出口條件, fns.length === 0, 最后一定執(zhí)行最左邊的函數(shù),然后把剩下的函數(shù)再經(jīng)過compose調(diào)用,

利用reduce實(shí)現(xiàn)。
具體實(shí)現(xiàn)代碼點(diǎn)擊這里,一行實(shí)現(xiàn),而且還是用正向的 reduce。

const compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args)))

作者其實(shí)用例子做了解釋,可以看下reduce 迭代的方向是從左往右的,而compose 要求執(zhí)行的方向是從從右往左。對數(shù)組中每一項(xiàng)執(zhí)行函數(shù),正常情況下都應(yīng)該放回執(zhí)行結(jié)果,比如(v, f) => f(v),返回f(v)執(zhí)行結(jié)果,這里是(f, g) => (...args) => f(g(...args))返回一個(gè)函數(shù)(...args) => f(g(...args)),這樣就可以保證后面的函數(shù)g在被作為參數(shù)傳入時(shí)比前面的函數(shù)f先執(zhí)行。

簡單利用前面的組合兩個(gè)函數(shù)的例子分析一下。

...
composeFunc = compose(getFirst, trace, reverse);
composeFunc(arr);
  

主要看reduce 函數(shù)里面的執(zhí)行過程:

入口 composeFunc(arr), 第一次迭代,reduce函數(shù)執(zhí)行 (getFirst, trace) => (...args)=>getFirst(trace(...args)),函數(shù)(...args)=>getFirst(trace(...args))作為下一次迭代中累計(jì)器f的值。

第二次迭代,reduce函數(shù)中

 f == (...args)=>getFirst(trace(...args))
 g == reverse。
 // 替換一下 (f, g) => (...args) => f(g(...args))
((...args)=>getFirst(trace(...args)), reverse) => (...args) => ((...args)=>getFirst(trace(...args)))(reverse(...args))

迭代結(jié)束,最后得到的comoseFunc就是

   // 對照第二次的執(zhí)行結(jié)果, (...args) => f(g(...args))

  (...args) => ((...args)=>getFirst(trace(...args)))(reverse(...args))

調(diào)用函數(shù)composeFunc(arr)。

(arr) => ((...args)=>getFirst(trace(...args)))(reverse(arr))

===》reverse(arr) 執(zhí)行結(jié)果[3, 2, 1] 作為參數(shù)

 ((...args)=>getFirst(trace(...args)))([3,2,1])

==》入?yún)⒄{(diào)用函數(shù)

   getFirst(trace[3,2,1])

===》 

   getFirst([3, 2, 1])

===》

   結(jié)果為 3

非常巧妙的把后一個(gè)函數(shù)的執(zhí)行結(jié)果作為包裹著前面函數(shù)的空函數(shù)的參數(shù),傳入執(zhí)行。其中大量用到下面的結(jié)構(gòu)

((arg)=> f(arg))(arg) 
// 轉(zhuǎn)換一下。
  (function(x) {
     return f(x)
  })(x)

最后

無論是compose, 還是后面提到的pipe,概念非常簡單,都可以使用非常巧妙的方式實(shí)現(xiàn)(大部分使用reduce),而且在編程中很大程度上簡化代碼。最后列出優(yōu)秀框架中使用compose的示例:

redux/compose

koa-Compose

underscorejs/compose

參考鏈接

Creating an ES6ish Compose in Javascript

compose.js

Optimization-killers

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/102266.html

相關(guān)文章

  • 函數(shù)編程組合

    摘要:在函數(shù)式編程的組合中,我們是從右到左執(zhí)行的,上述的例子中我們借助函數(shù)實(shí)現(xiàn)組合,當(dāng)然,我們也可以用自己的方式實(shí)現(xiàn)。小結(jié)函數(shù)式編程隨著多核的發(fā)展,開始再次出現(xiàn)在我們的視野中,有時(shí)候也會(huì)擔(dān)心過于吹捧函數(shù)式,反而落入俗套。 程序的本質(zhì)是什么?數(shù)據(jù)結(jié)構(gòu)+算法?。?!我想這也是很多程序員給出的答案,我自己也認(rèn)可這一觀點(diǎn),當(dāng)我們了解了某一門編程語之后,接下來我們面對的往往是數(shù)據(jù)結(jié)構(gòu)和算法的學(xué)習(xí)。而現(xiàn)在...

    Jinkey 評論0 收藏0
  • JavaScript函數(shù)編程函數(shù)組合函數(shù)compose和pipe的實(shí)現(xiàn)

    摘要:函數(shù)組合是函數(shù)式編程中非常重要的思想,它的實(shí)現(xiàn)的思路也沒有特別復(fù)雜。前者從左向右組合函數(shù),后者方向相反。下面就是一個(gè)最簡單的可以組合兩個(gè)函數(shù)的在實(shí)際應(yīng)用中,只能組合兩個(gè)函數(shù)的組合函數(shù)顯然不能滿足要求,我們需要可以組合任意個(gè)函數(shù)的組合函數(shù)。 函數(shù)組合是函數(shù)式編程中非常重要的思想,它的實(shí)現(xiàn)的思路也沒有特別復(fù)雜。有兩種函數(shù)組合的方式,一種是pipe,另一種是compose。前者從左向右組合函...

    Cristalven 評論0 收藏0
  • JS每日一題:函數(shù)編程中代碼組合(compose)如何理解?

    摘要:期函數(shù)式編程中代碼組合如何理解定義顧名思義,在函數(shù)式編程中,就是將幾個(gè)有特點(diǎn)的函數(shù)拼湊在一起,讓它們結(jié)合,產(chǎn)生一個(gè)嶄新的函數(shù)代碼理解一個(gè)將小寫轉(zhuǎn)大寫的函數(shù)一個(gè)在字符后加的函數(shù)將兩個(gè)函數(shù)組合起來這里假設(shè)我們實(shí)現(xiàn)了每日一題每日一題顯示結(jié)果里上面 20190315期 函數(shù)式編程中代碼組合(compose)如何理解? 定義: 顧名思義,在函數(shù)式編程中,Compose就是將幾個(gè)有特點(diǎn)的函數(shù)拼湊在...

    Kaede 評論0 收藏0
  • 翻譯連載 | JavaScript輕量級函數(shù)編程-第4章:組合函數(shù) |《你不知道的JS》姊妹篇

    摘要:把數(shù)據(jù)的流向想象成糖果工廠的一條傳送帶,每一次操作其實(shí)都是冷卻切割包裝糖果中的一步。在該章節(jié)中,我們將會(huì)用糖果工廠的類比來解釋什么是組合。糖果工廠靠這套流程運(yùn)營的很成功,但是和所有的商業(yè)公司一樣,管理者們需要不停的尋找增長點(diǎn)。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 關(guān)于譯者:這是一個(gè)流淌...

    JowayYoung 評論0 收藏0
  • JavaScript函數(shù)編程,真香之組合(一)

    摘要:組合的概念是非常直觀的,并不是函數(shù)式編程獨(dú)有的,在我們生活中或者前端開發(fā)中處處可見。其實(shí)我們函數(shù)式編程里面的組合也是類似,函數(shù)組合就是一種將已被分解的簡單任務(wù)組織成復(fù)雜的整體過程。在函數(shù)式編程的世界中,有這樣一種很流行的編程風(fēng)格。 JavaScript函數(shù)式編程,真香之認(rèn)識函數(shù)式編程(一) 該系列文章不是針對前端新手,需要有一定的編程經(jīng)驗(yàn),而且了解 JavaScript 里面作用域,閉...

    mengbo 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<