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

資訊專欄INFORMATION COLUMN

翻譯連載 | 附錄 B: 謙虛的 Monad-《JavaScript輕量級函數(shù)式編程》 |《你不知道

gaomysion / 2377人閱讀

摘要:就像我寫書的過程一樣,每個開發(fā)者在學(xué)習(xí)函數(shù)式編程的旅程中都會經(jīng)歷這個部分。類型在函數(shù)式編程中有一個巨大的興趣領(lǐng)域類型論,本書基本上完全遠離了該領(lǐng)域。在函數(shù)式編程中,像這樣涵蓋是很普遍的。

原文地址:Functional-Light-JS

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

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

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

JavaScript 輕量級函數(shù)式編程 附錄 B: 謙虛的 Monad

首先,我坦白:在開始寫以下內(nèi)容之前我并不太了解 Monad 是什么。我為了確認一些事情而犯了很多錯誤。如果你不相信我,去看看 這本書 Git 倉庫 中關(guān)于本章的提交歷史吧!

我在本書中囊括了所有涉及 Monad 的話題。就像我寫書的過程一樣,每個開發(fā)者在學(xué)習(xí)函數(shù)式編程的旅程中都會經(jīng)歷這個部分。

盡管其他函數(shù)式編程的著作差不多都把 Monad 作為開始,而我們卻只對它做了簡要說明,并基本以此結(jié)束本書。在輕量級函數(shù)式編程中我確實沒有遇到太多需要仔細考慮 Monad 的問題,這就是本文更有價值的原因。但是并不是說 Monad 是沒用的或者是不普遍的 —— 恰恰相反,它很有用,也很流行。

函數(shù)式編程界有一個小笑話,幾乎每個人都不得不在他們的文章或者博客里寫 Monad 是什么,把它拎出來寫就像是一個儀式。在過去的幾年里,人們把 Monad 描述為卷餅、洋蔥和各種各樣古怪的抽象概念。我肯定不會重蹈覆轍!

一個 Monad 僅僅是自函子 (endofunctor) 范疇中的一個 monoid

我們引用這句話來開場,所以把話題轉(zhuǎn)到這個引言上面似乎是很合適的。可是才不會這樣,我們不會討論 Monad 、endofunctor 或者范疇論。這句引言不僅故弄玄虛而且華而不實。

我只希望通過我們的討論,你不再害怕 Monad 這個術(shù)語或者這個概念了 —— 我曾經(jīng)怕了很長一段時間 —— 并在看到該術(shù)語時知道它是什么。你可能,也只是可能,會正確地使用到它們。

類型

在函數(shù)式編程中有一個巨大的興趣領(lǐng)域:類型論,本書基本上完全遠離了該領(lǐng)域。我不會深入到類型論,坦白的說,我沒有深入的能力,即使干了也吃力不討好。

但是我要說,Monad 基本上是一個值類型。

數(shù)字 42 有一個值類型(number),它帶有我們依賴的特征和功能。字符串 "42" 可能看起來很像,但是在編程里它有不同的用途。

在面向?qū)ο缶幊讨校?dāng)你有一組數(shù)據(jù)(甚至是一個多帶帶的離散值),并且想要給它綁上一些行為,那么你將創(chuàng)建一個對象或者類來表示 "type"。接著實例就成了該類型的一員。這種做法通常被稱為 “數(shù)據(jù)結(jié)構(gòu)”。

我將會非常寬泛的使用數(shù)據(jù)結(jié)構(gòu)這個概念,而且我斷定,當(dāng)我們在編程中為一個特定的值定義一組行為以及約束條件,并且將這些特征與值一起綁定在一個單一抽象概念上時,我們可能會覺得很有用。這樣,當(dāng)我們在編程中使用一個或多個這種值的時候,它們的行為會自然的出現(xiàn),并且會使它們更方便的工作。方便的是,對你的代碼的讀者來說,是更有描述性和聲明性的。

Monad 是一種數(shù)據(jù)結(jié)構(gòu)。是一種類型。它是一組使處理某個值變得可預(yù)測的特定行為。

回顧第 8 章,我們談到了函子(functor):包括一個值和一個用來對構(gòu)成函子的數(shù)據(jù)執(zhí)行操作的類 map 實用函數(shù)。Monad 是一個包含一些額外行為的函子(functor)。

松散接口

實際上,Monad 并不是單一的數(shù)據(jù)類型,它更像是相關(guān)聯(lián)的數(shù)據(jù)類型集合。它是一種根據(jù)不同值的需要而用不同方式實現(xiàn)的接口。每種實現(xiàn)都是一種不同類型的 Monad。

例如,你可能閱讀 "Identity Monad"、"IO Monad"、"Maybe Monad"、"Either Monad" 或其他形形色色的字眼。他們中的每一個都有基本的 Monad 行為定義,但是它根據(jù)每個不同類型的 Monad 用例來繼承或者重寫交互行為。

可是它不僅僅是一個接口,因為它不只是使對象成為 Monad 的某些 API 方法的實現(xiàn)。對這些方法的交互的保障是必須的,是 monadic 的。這些眾所周知的常量對于使用 Monad 提高可讀性是至關(guān)重要的;另外,它是一個特殊的數(shù)據(jù)結(jié)構(gòu),讀者必須全部閱讀才能明白。

事實上,這些 Monad 方法的名字和真實接口授權(quán)的方式甚至沒有一個統(tǒng)一的標(biāo)準(zhǔn);Monad 更像是一個松散接口。有些人稱這些方法為 bind(..),有些稱它為 chain(..),還有些稱它為 flatMap(..),等等。

所以,Monad 是一個對象數(shù)據(jù)結(jié)構(gòu),并且有充足的方法(幾乎任何名稱或排序),至少滿足了 Monad 定義的主要行為需求。每一種 Monad 都基于最少數(shù)量的方法來進行不同的擴展。但是,因為它們在行為上都有重疊,所以一起使用兩種不同的 Monad 仍然是直截了當(dāng)和可控的。

從某種意義上說,Monad 更像是接口。

Maybe

在函數(shù)式編程中,像 Maybe 這樣涵蓋 Monad 是很普遍的。事實上,Maybe Monad 是另外兩個更簡單的 Monad 的搭配:Just 和 Nothing。

既然 Monad 是一個類型,你可能認為我們應(yīng)該定義 Maybe 作為一個要被實例化的類。這雖然是一種有效的方法,但是它引入了 this 綁定的問題,所以在這里我不想討論;相反,我打算使用一個簡單的函數(shù)和對象的實現(xiàn)方式。

以下是 Maybe 的最簡單的實現(xiàn):

var Maybe = { Just, Nothing, of/* 又稱:unit,pure */: Just };

function Just(val) {
    return { map, chain, ap, inspect };

    // *********************

    function map(fn) { return Just( fn( val ) ); }
    // 又稱:bind, flatMap
    function chain(fn) { return fn( val ); }
    function ap(anotherMonad) { return anotherMonad.map( val ); }

    function inspect() {
        return `Just(${ val })`;
    }
}

function Nothing() {
    return { map: Nothing, chain: Nothing, ap: Nothing, inspect };

    // *********************

    function inspect() {
        return "Nothing";
    }
}

注意: inspect(..) 方法只用于我們的示例中。從 Monad 的角度來說,它并沒有任何意義。

如果現(xiàn)在大部分都沒有意義的話,不要擔(dān)心。我們將會更專注的說明我們可以用它做什么,而不是過多的深入 Monad 背后的設(shè)計細節(jié)和理論。

所有的 Monad 一樣,任何含有 Just(..)Nothing() 的 Monad 實例都有 map(..)、chain(..)(也叫 bind(..) 或者 flatMap(..))和 ap(..) 方法。這些方法及其行為的目的在于提供多個 Monad 實例一起工作的標(biāo)準(zhǔn)化方法。你將會注意到,無論 Just(..) 實例拿到的是怎樣的一個 val 值, Just(..) 實例都不會去改變它。所有的方法都會創(chuàng)建一個新的 Monad 實例而不是改變它。

Maybe 是這兩個 Monad 的結(jié)合。如果一個值是非空的,它是 Just(..) 的實例;如果該值是空的,它則是 Nothing() 的實例。注意,這里由你的代碼來決定 "空" 的意思,我們不做強制限制。下一節(jié)會詳細介紹這一點。

但是 Monad 的價值在于不論我們有 Just(..) 實例還是 Nothing() 實例,我們使用的方法都是一樣的。Nothing() 實例對所有的方法都有空操作定義。所以如果 Monad 實例出現(xiàn)在 Monad 操作中,它就會對 Monad 操作起短路(short-circuiting)作用。

Maybe 這個抽象概念的作用是隱式地封裝了操作和無操作的二元性。

與眾不同的 Maybe

JavaScript Maybe Monad 的許多實現(xiàn)都包含 nullundefined 的檢查(通常在 map(..)中),如果是空的話,就跳過該 Monad 的特性行為。事實上,Maybe 被聲稱是有價值的,因為它自動地封裝了空值檢查得以在某種程度上短路了它的特性行為。

這是 Maybe 的典型說明:

// 代替不穩(wěn)定的 `console.log( someObj.something.else.entirely )`:

Maybe.of( someObj )
.map( prop( "something" ) )
.map( prop( "else" ) )
.map( prop( "entirely" ) )
.map( console.log );

換句話說,如果我們在鏈?zhǔn)讲僮髦械娜魏我画h(huán)得到一個 null 或者 undefined 值,Maybe 會智能的切換到空操作模式 —— 它現(xiàn)在是一個 Nothing() Monad 實例! —— 把剩余的鏈?zhǔn)讲僮鞫纪V沟?。如果一些屬性丟失或者是空的話,嵌套的屬性訪問能安全的拋出 JS 異常。這是非??岬亩液軐嵱谩?/p>

但是,我們這樣實現(xiàn)的 Maybe 不是一個純 Monad。

Monad 的核心思想是,它必須對所有的值都是有效的,不能對值做任何檢查 —— 甚至是空值檢查。所以為了方便,這些其他的實現(xiàn)都是走的捷徑。這是無關(guān)緊要的。但是當(dāng)學(xué)習(xí)一些東西的時候,你應(yīng)該先學(xué)習(xí)它的最純粹的形式,然后再學(xué)習(xí)更復(fù)雜的規(guī)則。

我早期提供的 Maybe Monad 的實現(xiàn)不同于其他的 Maybe,就是它沒有空置檢查。另外,我們將 Maybe 作為 Just(..)Nothing() 的非嚴(yán)格意義上的結(jié)合。

等一下,如果我們沒有自動短路,那 Maybe 是怎么起作用的呢??。窟@似乎就是它的全部意義。

不要擔(dān)心,我們可以從外部提供簡單的空值檢查,Maybe Monad 其他的短路行為也還是可以很好的工作的。你可以在之前做一些 someObj.something.else.entirely 屬性嵌套,但是我們可以做的更 “正確”:

function isEmpty(val) {
    return val === null || val === undefined;
}

var safeProp = curry( function safeProp(prop,obj){
    if (isEmpty( obj[prop] )) return Maybe.Nothing();
    return Maybe.of( obj[prop] );
} );

Maybe.of( someObj )
.chain( safeProp( "something" ) )
.chain( safeProp( "else" ) )
.chain( safeProp( "entirely" ) )
.map( console.log );

我們設(shè)計了一個用于空值檢查的 safeProp(..) 函數(shù),并選擇了 Nothing() Monad 實例?;蛘甙阎蛋b在 Just(..) 實例中(通過 Maybe.of(..))。然后我們用 chain(..) 替代 map(..),它知道如何 “展開” safeProp(..) 返回的 Monad。

當(dāng)遇到空值的時候,我們得到了一連串相同的短路。只是我們把這個邏輯從 Maybe 中排除了。

不管返回哪種類型的 Monad,我們的 map(..)chain(..) 方法都有不變且可預(yù)測的反饋,這就是 Monad,尤其是 Maybe Monad 的好處。這難道不酷嗎?

Humble

現(xiàn)在我們對 Maybe 和它的作用有了更多的了解,我將會在它上面加一些小的改動 —— 我將通過設(shè)計 Maybe + Humble Monad 來添加一些轉(zhuǎn)折并且加一些詼諧的元素。從技術(shù)上來說,Humble(..) 并不是一個 Monad,而是一個產(chǎn)生 Maybe Monad 實例的工廠函數(shù)。

Humble 是一個使用 Maybe 來跟蹤 egoLevel 數(shù)字狀態(tài)的數(shù)據(jù)結(jié)構(gòu)包裝器。具體來說,Humble(..) 只有在他們自身的水平值足夠低(少于 42)到被認為是 Humble 的時候才會執(zhí)行生成的 Monad 實例;否則,它就是一個 Nothing() 空操作。這聽起來真的和 Maybe 很像!

這是一個 Maybe + Humble Monad 工廠函數(shù):

function Humble(egoLevel) {
    // 接收任何大于等于 42 的數(shù)字
    return !(Number( egoLevel ) >= 42) ?
        Maybe.of( egoLevel ) :
        Maybe.Nothing();
}

你可能會注意到,這個工廠函數(shù)有點像 safeProp(..),因為,它使用一個條件來決定是選擇 Maybe 的 Just(..) 還是 Nothing()。

讓我們來看一個基礎(chǔ)用法的例子:

var bob = Humble( 45 );
var alice = Humble( 39 );

bob.inspect();                            // Nothing
alice.inspect();                        // Just(39)

如果 Alice 贏得了一個大獎,現(xiàn)在是不是在為自己感到自豪呢?

function winAward(ego) {
    return Humble( ego + 3 );
}

alice = alice.chain( winAward );
alice.inspect();                        // Nothing

Humble( 39 + 3 ) 創(chuàng)建了一個 chain(..) 返回的 Nothing() Monad 實例,所以現(xiàn)在 Alice 不再有 Humble 的資格了。

現(xiàn)在,我們來用一些 Monad :

var bob = Humble( 41 );
var alice = Humble( 39 );

var teamMembers = curry( function teamMembers(ego1,ego2){
    console.log( `Our humble team"s egos: ${ego1} ${ego2}` );
} );

bob.map( teamMembers ).ap( alice );
// Humble 隊列:41 39

由于 teamMembers(..) 是柯里化的,bob.map(..) 的調(diào)用傳入了 bob 自身的級別(41),并且創(chuàng)建了一個被其余的方法包裝的 Monad 實例。在 這個 Monad 中調(diào)用的 ap(alice) 調(diào)用了 alice.map(..),并且傳遞給來自 Monad 的函數(shù)。這樣做的效果是,Monad 的值已經(jīng)提供給了 teamMembers(..) 函數(shù),并且把顯示的結(jié)果給打印了出來。

然而,如果一個 Monad 或者兩個 Monad 實際上是 Nothing() 實例(因為它們本身的水平值太高了):

var frank = Humble( 45 );

bob.map( teamMembers ).ap( frank );

frank.map( teamMembers ).ap( bob );

teamMembers(..) 永遠不會被調(diào)用(也沒有信息被打印出來),因為,frank 是一個 Nothing() 實例。這就是 Maybe monad 的作用,我們的 Humble(..) 工廠函數(shù)允許我們根據(jù)自身的水平來選擇。贊!

Humility

再來一個例子來說明 Maybe + Humble 數(shù)據(jù)結(jié)構(gòu)的行為:

function introduction() {
    console.log( "I"m just a learner like you! :)" );
}

var egoChange = curry( function egoChange(amount,concept,egoLevel) {
    console.log( `${amount > 0 ? "Learned" : "Shared"} ${concept}.` );
    return Humble( egoLevel + amount );
} );

var learn = egoChange( 3 );

var learner = Humble( 35 );

learner
.chain( learn( "closures" ) )
.chain( learn( "side effects" ) )
.chain( learn( "recursion" ) )
.chain( learn( "map/reduce" ) )
.map( introduction );
// 學(xué)習(xí)閉包
// 學(xué)習(xí)副作用
// 歇息遞歸

不幸的是,學(xué)習(xí)過程看起來已經(jīng)縮短了。我發(fā)現(xiàn)學(xué)習(xí)一大堆東西而不和別人分享,會使自我太膨脹,這對你的技術(shù)是不利的。

讓我們嘗試一個更好的方法:

var share = egoChange( -2 );

learner
.chain( learn( "closures" ) )
.chain( share( "closures" ) )
.chain( learn( "side effects" ) )
.chain( share( "side effects" ) )
.chain( learn( "recursion" ) )
.chain( share( "recursion" ) )
.chain( learn( "map/reduce" ) )
.chain( share( "map/reduce" ) )
.map( introduction );
// 學(xué)習(xí)閉包
// 分享閉包
// 學(xué)習(xí)副作用
// 分享副作用
// 學(xué)習(xí)遞歸
// 分享遞歸
// 學(xué)習(xí) map/reduce
// 分享 map/reduce
// 我只是一個像你一樣的學(xué)習(xí)者 :)

在學(xué)習(xí)中分享。是學(xué)習(xí)更多并且能夠?qū)W的更好的最佳方法。

總結(jié)

說了這么多,那什么是 Monad ?

Monad 是一個值類型,一個接口,一個有封裝行為的對象數(shù)據(jù)結(jié)構(gòu)。

但是這些定義中沒有一個是有用的。這里嘗試做一個更好的解釋:Monad 是一個用更具有聲明式的方式圍繞一個值來組織行為的方法。

和這本書中的其他部分一樣,在有用的地方使用 Monad,不要因為每個人都在函數(shù)式編程中討論他們而使用他們。Monad 不是萬金油,但它確實提供了一些有用的實用函數(shù)。

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

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

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

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

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

相關(guān)文章

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

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

    Miracle 評論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
  • 全本 | iKcamp翻譯 | 《JavaScript 量級函數(shù)編程》|《你不知道JS》姊妹篇

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

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

    摘要:所以我覺得函數(shù)式編程領(lǐng)域更像學(xué)者的領(lǐng)域。函數(shù)式編程的原則是完善的,經(jīng)過了深入的研究和審查,并且可以被驗證。函數(shù)式編程是編寫可讀代碼的最有效工具之一可能還有其他。我知道很多函數(shù)式編程編程者會認為形式主義本身有助于學(xué)習(xí)。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson?。 禮ou-Dont-Know-JS》作者 關(guān)于譯者:這是一個流淌著滬江血液...

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

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

    Amos 評論0 收藏0

發(fā)表評論

0條評論

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