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

資訊專欄INFORMATION COLUMN

翻譯連載 | 附錄 A:Transducing(下)-《JavaScript輕量級函數(shù)式編程》 |《

bluesky / 936人閱讀

摘要:譯者團隊排名不分先后阿希冬青蘿卜萌萌輕量級函數(shù)式編程附錄下組合柯里化這一步是最棘手的。該片段中的組合函數(shù)被稱為,而不是。上一章翻譯連載附錄上輕量級函數(shù)式編程你不知道的姊妹篇原創(chuàng)新書移動前端高效開發(fā)實戰(zhàn)已在亞馬遜京東當當開售。

原文地址:Functional-Light-JS

原文作者:Kyle Simpson-《You-Dont-Know-JS》作者

關(guān)于譯者:這是一個流淌著滬江血液的純粹工程:認真,是 HTML 最堅實的梁柱;分享,是 CSS 里最閃耀的一瞥;總結(jié),是 JavaScript 中最嚴謹?shù)倪壿?。?jīng)過捶打磨練,成就了本書的中文版。本書包含了函數(shù)式編程之精髓,希望可以幫助大家在學習函數(shù)式編程的道路上走的更順暢。比心。

譯者團隊(排名不分先后):阿希、blueken、brucecham、cfanlife、dail、kyoko-df、l3ve、lilins、LittlePineapple、MatildaJin、冬青、pobusama、Cherry、蘿卜、vavd317、vivaxy、萌萌、zhouyao

JavaScript 輕量級函數(shù)式編程 附錄 A:Transducing(下) 組合柯里化

這一步是最棘手的。所以請慢慢的用心的閱讀。

讓我們看看沒有將 listCombination(..) 傳遞給柯里化函數(shù)的樣子:

var x = curriedMapReducer( strUppercase );
var y = curriedFilterReducer( isLongEnough );
var z = curriedFilterReducer( isShortEnough );

看看這三個中間函數(shù) x(..), y(..)z(..)。每個函數(shù)都期望得到一個單一的組合函數(shù)并產(chǎn)生一個 reducer 函數(shù)。

記住,如果我們想要所有這些的獨立的 reducer,我們可以這樣做:

var upperReducer = x( listCombination );
var longEnoughReducer = y( listCombination );
var shortEnoughReducer = z( listCombination );

但是,如果你調(diào)用 y(z),會得到什么呢?當把 z 傳遞給 y(..) 調(diào)用,而不是 combinationFn(..) 時會發(fā)生什么呢?這個返回的 reducer 函數(shù)內(nèi)部看起來像這樣:

function reducer(list,val) {
    if (isLongEnough( val )) return z( list, val );
    return list;
}

看到 z(..) 里面的調(diào)用了嗎? 這看起來應(yīng)該是錯誤的,因為 z(..) 函數(shù)應(yīng)該只接收一個參數(shù)(combinationFn(..)),而不是兩個參數(shù)(list 和 val)。這和要求不匹配。不行。

我們來看看組合 y(z(listCombination))。我們將把它分成兩個不同的步驟:

var shortEnoughReducer = z( listCombination );
var longAndShortEnoughReducer = y( shortEnoughReducer );

我們創(chuàng)建 shortEnoughReducer(..),然后將它作為 combinationFn(..) 傳遞給 y(..),生成 longAndShortEnoughReducer(..)。多讀幾遍,直到理解。

現(xiàn)在想想: shortEnoughReducer(..)longAndShortEnoughReducer(..) 的內(nèi)部構(gòu)造是什么樣的呢?你能想得到嗎?

// shortEnoughReducer, from z(..):
function reducer(list,val) {
    if (isShortEnough( val )) return listCombination( list, val );
    return list;
}

// longAndShortEnoughReducer, from y(..):
function reducer(list,val) {
    if (isLongEnough( val )) return shortEnoughReducer( list, val );
    return list;
}

你看到 shortEnoughReducer(..) 替代了 longAndShortEnoughReducer(..) 里面 listCombination(..) 的位置了嗎? 為什么這樣也能運行?

因為 reducer(..) 的“形狀”和 listCombination(..) 的形狀是一樣的。 換句話說,reducer 可以用作另一個 reducer 的組合函數(shù); 它們就是這樣組合起來的! listCombination(..) 函數(shù)作為第一個 reducer 的組合函數(shù),這個 reducer 又可以作為組合函數(shù)給下一個 reducer,以此類推。

我們用幾個不同的值來測試我們的 longAndShortEnoughReducer(..)

longAndShortEnoughReducer( [], "nope" );
// []

longAndShortEnoughReducer( [], "hello" );
// ["hello"]

longAndShortEnoughReducer( [], "hello world" );
// []

longAndShortEnoughReducer(..) 會過濾出不夠長且不夠短的值,它在同一步驟中執(zhí)行這兩個過濾。這是一個組合 reducer!

再花點時間消化下。

現(xiàn)在,把 x(..) (生成大寫 reducer 的產(chǎn)生器)加入組合:

var longAndShortEnoughReducer = y( z( listCombination) );
var upperLongAndShortEnoughReducer = x( longAndShortEnoughReducer );

正如 upperLongAndShortEnoughReducer(..) 名字所示,它同時執(zhí)行所有三個步驟 - 一個映射和兩個過濾器!它內(nèi)部看起來是這樣的:

// upperLongAndShortEnoughReducer:
function reducer(list,val) {
    return longAndShortEnoughReducer( list, strUppercase( val ) );
}

一個字符串類型的 val 被傳入,由 strUppercase(..) 轉(zhuǎn)換成大寫,然后傳遞給 longAndShortEnoughReducer(..)。該函數(shù)只有在 val 滿足足夠長且足夠短的條件時才將它添加到數(shù)組中。否則數(shù)組保持不變。

我花了幾個星期來思考分析這種雜耍似的操作。所以別著急,如果你需要在這好好研究下,重新閱讀個幾(十幾個)次。慢慢來。

現(xiàn)在來驗證一下:

upperLongAndShortEnoughReducer( [], "nope" );
// []

upperLongAndShortEnoughReducer( [], "hello" );
// ["HELLO"]

upperLongAndShortEnoughReducer( [], "hello world" );
// []

這個 reducer 成功的組合了和 map 和兩個 filter,太棒了!

讓我們回顧一下我們到目前為止所做的事情:

var x = curriedMapReducer( strUppercase );
var y = curriedFilterReducer( isLongEnough );
var z = curriedFilterReducer( isShortEnough );

var upperLongAndShortEnoughReducer = x( y( z( listCombination ) ) );

words.reduce( upperLongAndShortEnoughReducer, [] );
// ["WRITTEN","SOMETHING"]

這已經(jīng)很酷了,但是我們可以讓它更好。

x(y(z( .. ))) 是一個組合。我們可以直接跳過中間的 x / y / z 變量名,直接這么表示該組合:

var composition = compose(
    curriedMapReducer( strUppercase ),
    curriedFilterReducer( isLongEnough ),
    curriedFilterReducer( isShortEnough )
);

var upperLongAndShortEnoughReducer = composition( listCombination );

words.reduce( upperLongAndShortEnoughReducer, [] );
// ["WRITTEN","SOMETHING"]

我們來考慮下該組合函數(shù)中“數(shù)據(jù)”的流動:

listCombination(..) 作為組合函數(shù)傳入,構(gòu)造 isShortEnough(..) 過濾器的 reducer。

然后,所得到的 reducer 函數(shù)作為組合函數(shù)傳入,繼續(xù)構(gòu)造 isShortEnough(..) 過濾器的 reducer。

最后,所得到的 reducer 函數(shù)作為組合函數(shù)傳入,構(gòu)造 strUppercase(..) 映射的 reducer。

在前面的片段中,composition(..) 是一個組合函數(shù),期望組合函數(shù)來形成一個 reducer;而這個 composition(..) 有一個特殊的標簽:transducer。給 transducer 提供組合函數(shù)產(chǎn)生組合的 reducer:

// TODO:檢查 transducer 是產(chǎn)生 reducer 還是它本身就是 reducer

var transducer = compose(
    curriedMapReducer( strUppercase ),
    curriedFilterReducer( isLongEnough ),
    curriedFilterReducer( isShortEnough )
);

words
.reduce( transducer( listCombination ), [] );
// ["WRITTEN","SOMETHING"]

注意:我們應(yīng)該好好觀察下前面兩個片段中的 compose(..) 順序,這地方有點難理解?;叵胍幌拢谖覀兊脑际纠?,我們先 map(strUppercase) 然后 filter(isLongEnough) ,最后 filter(isShortEnough);這些操作實際上也確實按照這個順序執(zhí)行的。但在第 4 章中,我們了解到,compose(..) 通常是以相反的順序運行。那么為什么我們不需要反轉(zhuǎn)這里的順序來獲得同樣的期望結(jié)果呢?來自每個 reducer 的 combinationFn(..) 的抽象反轉(zhuǎn)了操作順序。所以和直覺相反,當組合一個 tranducer 時,你只需要按照實際的順序組合就好!

列表組合:純與不純

我們再來看一下我們的 listCombination(..) 組合函數(shù)的實現(xiàn):

function listCombination(list,val) {
    return list.concat( [val] );
}

雖然這種方法是純的,但它對性能有負面影響。首先,它創(chuàng)建臨時數(shù)組來包裹 val。然后,concat(..) 方法創(chuàng)建一個全新的數(shù)組來連接這個臨時數(shù)組。每一步都會創(chuàng)建和銷毀的很多數(shù)組,這不僅對 CPU 不利,也會造成 GC 內(nèi)存的流失。

下面是性能更好但是不純的版本:

function listCombination(list,val) {
    list.push( val );
    return list;
}

多帶帶的考慮下 listCombination(..) ,毫無疑問,這是不純的,這通常是我們想要避免的。但是,我們應(yīng)該考慮一個更大的背景。

listCombination(..) 不是我們完全有交互的函數(shù)。我們不直接在程序中的任何地方使用它,而只是在 transducing 的過程中使用它。

回到第 5 章,我們定義純函數(shù)來減少副作用的目標只是限制在應(yīng)用的 API 層級。對于底層實現(xiàn),只要沒有違反對外部是純函數(shù),就可以在函數(shù)內(nèi)為了性能而變得不純。

listCombination(..) 更多的是轉(zhuǎn)換的內(nèi)部實現(xiàn)細節(jié)。實際上,它通常由 transducing 庫提供!而不是你的程序中進行交互的頂層方法。

底線:我認為甚至使用 listCombination(..) 的性能最優(yōu)但是不純的版本也是完全可以接受的。只要確保你用代碼注釋記錄下它不純即可!

可選的組合

到目前為止,這是我們用轉(zhuǎn)換所得到的:

words
.reduce( transducer( listCombination ), [] )
.reduce( strConcat, "" );
// 寫點什么

這已經(jīng)非常棒了,但是我們還藏著最后一個的技巧。坦白來說,我認為這部分能夠讓你迄今為止付出的所有努力變得值得。

我們可以用某種方式實現(xiàn)只用一個 reduce(..) 來“組合”這兩個 reduce(..) 嗎? 不幸的是,我們并不能將 strConcat(..) 添加到 compose(..) 調(diào)用中; 它的“形狀”不適用于那個組合。

但是讓我們來看下這兩個功能:

function strConcat(str1,str2) { return str1 + str2; }

function listCombination(list,val) { list.push( val ); return list; }

如果你用心觀察,可以看出這兩個功能是如何互換的。它們以不同的數(shù)據(jù)類型運行,但在概念上它們也是一樣的:將兩個值組合成一個。

換句話說, strConcat(..) 是一個組合函數(shù)!

這意味著如果我們的最終目標是獲得字符串連接而不是數(shù)組,我們就可以用它代替 listCombination(..)

words.reduce( transducer( strConcat ), "" );
// 寫點什么

Boom! 這就是 transducing。

最后

深吸一口氣,確實有很多要消化。

放空我們的大腦,讓我們把注意力轉(zhuǎn)移到如何在我們的程序中使用轉(zhuǎn)換,而不是關(guān)心它的工作原理。

回想起我們之前定義的輔助函數(shù),為清楚起見,我們重新命名一下:

var transduceMap = curry( function mapReducer(mapperFn,combinationFn){
    return function reducer(list,v){
        return combinationFn( list, mapperFn( v ) );
    };
} );

var transduceFilter = curry( function filterReducer(predicateFn,combinationFn){
    return function reducer(list,v){
        if (predicateFn( v )) return combinationFn( list, v );
        return list;
    };
} );

還記得我們這樣使用它們:

var transducer = compose(
    transduceMap( strUppercase ),
    transduceFilter( isLongEnough ),
    transduceFilter( isShortEnough )
);

transducer(..) 仍然需要一個組合函數(shù)(如 listCombination(..)strConcat(..))來產(chǎn)生一個傳遞給 reduce(..) (連同初始值)的 transduce-reducer 函數(shù)。

但是為了更好的表達所有這些轉(zhuǎn)換步驟,我們來做一個 transduce(..) 工具來為我們做這些步驟:

function transduce(transducer,combinationFn,initialValue,list) {
    var reducer = transducer( combinationFn );
    return list.reduce( reducer, initialValue );
}

這是我們的運行示例,梳理如下:

var transducer = compose(
    transduceMap( strUppercase ),
    transduceFilter( isLongEnough ),
    transduceFilter( isShortEnough )
);

transduce( transducer, listCombination, [], words );
// ["WRITTEN","SOMETHING"]

transduce( transducer, strConcat, "", words );
// 寫點什么

不錯,嗯! 看到 listCombination(..)strConcat(..) 函數(shù)可以互換使用組合函數(shù)了嗎?

Transducers.js

最后,我們來說明我們運行的例子,使用sensors-js庫(https://github.com/cognitect-... ):

var transformer = transducers.comp(
    transducers.map( strUppercase ),
    transducers.filter( isLongEnough ),
    transducers.filter( isShortEnough )
);

transducers.transduce( transformer, listCombination, [], words );
// ["WRITTEN","SOMETHING"]

transducers.transduce( transformer, strConcat, "", words );
// WRITTENSOMETHING

看起來幾乎與上述相同。

注意: 上面的代碼段使用 transformers.comp(..) ,因為這個庫提供這個 API,但在這種情況下,我們從第 4 章的 compose(..) 也將產(chǎn)生相同的結(jié)果。換句話說,組合本身不是 transducing 敏感的操作。

該片段中的組合函數(shù)被稱為 transformer ,而不是 transducer。那是因為如果我們直接調(diào)用 transformer(listCombination)(或 transformer(strConcat)),那么我們不會像以前那樣得到一個直觀的 transduce-reducer 函數(shù)。

transducers.map(..)transducers.filter(..) 是特殊的輔助函數(shù),可以將常規(guī)的斷言函數(shù)或映射函數(shù)轉(zhuǎn)換成適用于產(chǎn)生特殊變換對象的函數(shù)(里面包含了 reducer 函數(shù));這個庫使用這些變換對象進行轉(zhuǎn)換。此轉(zhuǎn)換對象抽象的額外功能超出了我們將要探索的內(nèi)容,請參閱該庫的文檔以獲取更多信息。

由于 transformer(..) 產(chǎn)生一個變換對象,而不是一個典型的二元 transduce-reducer 函數(shù),該庫還提供 toFn(..) 來使變換對象適應(yīng)本地數(shù)組的 reduce(..) 方法:

words.reduce(
    transducers.toFn( transformer, strConcat ),
    ""
);
// WRITTENSOMETHING

into(..) 是另一個提供的輔助函數(shù),它根據(jù)指定的空/初始值的類型自動選擇默認的組合函數(shù):

transducers.into( [], transformer, words );
// ["WRITTEN","SOMETHING"]

transducers.into( "", transformer, words );
// WRITTENSOMETHING

當指定一個空數(shù)組 [] 時,內(nèi)部的 transduce(..) 使用一個默認的函數(shù)實現(xiàn),這個函數(shù)就像我們的 listCombination(..)。但是當指定一個空字符串 “” 時,會使用像我們的 strConcat(..) 這樣的方法。這很酷!

如你所見,transducers-js 庫使轉(zhuǎn)換非常簡單。我們可以非常有效地利用這種技術(shù)的力量,而不至于陷入定義所有這些中間轉(zhuǎn)換器生產(chǎn)工具的繁瑣過程中去。

總結(jié)

Transduce 就是通過減少來轉(zhuǎn)換。更具體點,transduer 是可組合的 reducer。

我們使用轉(zhuǎn)換來組合相鄰的map(..)filter(..)reduce(..) 操作。我們首先將 map(..)filter(..) 表示為 reduce(..),然后抽象出常用的組合操作來創(chuàng)建一個容易組合的一致的 reducer 生成函數(shù)。

transducing 主要提高性能,如果在延遲序列(異步 observables)中使用,則這一點尤為明顯。

但是更廣泛地說,transducing 是我們針對那些不能被直接組合的函數(shù),使用的一種更具聲明式風格的方法。否則這些函數(shù)將不能直接組合。如果使用這個技術(shù)能像使用本書中的所有其他技術(shù)一樣用的恰到好處,代碼就會顯得更清晰,更易讀! 使用 transducer 進行單次 reduce(..) 調(diào)用比追蹤多個 reduce(..) 調(diào)用更容易理解。

【上一章】翻譯連載 | 附錄 A:Transducing(上)-《JavaScript輕量級函數(shù)式編程》 |《你不知道的JS》姊妹篇

iKcamp原創(chuàng)新書《移動Web前端高效開發(fā)實戰(zhàn)》已在亞馬遜、京東、當當開售。

iKcamp官網(wǎng):https://www.ikcamp.com
訪問官網(wǎng)更快閱讀全部免費分享課程:
《iKcamp出品|全網(wǎng)最新|微信小程序|基于最新版1.0開發(fā)者工具之初中級培訓教程分享》
《iKcamp出品|基于Koa2搭建Node.js實戰(zhàn)項目教程》
包含:文章、視頻、源代碼

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

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

相關(guān)文章

  • 翻譯連載 | 附錄 A:Transducing(上)-《JavaScript量級函數(shù)編程》 |《

    摘要:我不會把嚴格的稱為輕量級函數(shù)式編程,它更像是一個頂級的技巧。實際上,我認為這是你掌握了輕量級函數(shù)式編程后可以做的最好的例證之一。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 關(guān)于譯者:這是一個流淌著滬江血液的純粹工程:認真,是 HTML 最堅實的梁柱;分享,是 CSS 里最閃耀的一瞥;總結(jié),是 ...

    Amos 評論0 收藏0
  • 翻譯連載 |《你不知道的JS》姊妹篇 |《JavaScript 量級函數(shù)編程》- 引言&前言

    摘要:我稱之為輕量級函數(shù)式編程。序眾所周知,我是一個函數(shù)式編程迷。函數(shù)式編程有很多種定義。本書是你開啟函數(shù)式編程旅途的絕佳起點。事實上,已經(jīng)有很多從頭到尾正確的方式介紹函數(shù)式編程的書了。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson?。 禮ou-Dont-Know-JS》作者 譯者團隊(排名不分先后):阿希、blueken、brucecham、...

    2bdenny 評論0 收藏0
  • 翻譯連載 | 附錄 B: 謙虛的 Monad-《JavaScript量級函數(shù)編程》 |《你不知道

    摘要:就像我寫書的過程一樣,每個開發(fā)者在學習函數(shù)式編程的旅程中都會經(jīng)歷這個部分。類型在函數(shù)式編程中有一個巨大的興趣領(lǐng)域類型論,本書基本上完全遠離了該領(lǐng)域。在函數(shù)式編程中,像這樣涵蓋是很普遍的。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 關(guān)于譯者:這是一個流淌著滬江血液的純粹工程:認真,是 HTML...

    gaomysion 評論0 收藏0
  • 翻譯連載 | 附錄 C:函數(shù)編程函數(shù)庫-《JavaScript量級函數(shù)編程》 |《你不知道的J

    摘要:為了盡可能提升互通性,已經(jīng)成為函數(shù)式編程庫遵循的實際標準。與輕量級函數(shù)式編程的概念相反,它以火力全開的姿態(tài)進軍的函數(shù)式編程世界。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 關(guān)于譯者:這是一個流淌著滬江血液的純粹工程:認真,是 HTML 最堅實的梁柱;分享,是 CSS 里最閃耀的一瞥;總結(jié),...

    Miracle 評論0 收藏0
  • 全本 | iKcamp翻譯 | 《JavaScript 量級函數(shù)編程》|《你不知道的JS》姊妹篇

    摘要:本書主要探索函數(shù)式編程的核心思想。我們在中應(yīng)用的僅僅是一套基本的函數(shù)式編程概念的子集。我稱之為輕量級函數(shù)式編程。通常來說,關(guān)于函數(shù)式編程的書籍都熱衷于拓展閱讀者的知識面,并企圖覆蓋更多的知識點。,本書統(tǒng)稱為函數(shù)式編程者。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson - 《You-Dont-Know-JS》作者 譯者團隊(排名不分先后)...

    paney129 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<