iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 24
0
Software Development

Functional Programming in JS系列 第 24

Functor 4: 圖解 Box Data Type 之方法 map、flatMap、chain

Functor 對初學者來說實在有點難懂,所以不知不覺已來到第四篇,希望看完這一系列可以真的懂他在幹嘛。 基本上除了系列 1 之外,其他都是在探究 Box 這種 data type
https://ithelp.ithome.com.tw/upload/images/20200925/20106426cgJAqD2xtT.jpg
(↑ 不知道已出現幾次的 Box data type 圖)

Map

神奇的運算 map 能接受 Functor 當作輸入參數,回傳另一個 Box。

雖然前面其實已經說過這是什麼,但需要再強調複習一次
https://ithelp.ithome.com.tw/upload/images/20200925/20106426us8pdxIQqy.jpg

const Box = f => ({
    map: g => Box( x => g(f(x)) ),
}

FlatMap

un-nest 扁平化,接受 Functor 當作參數,回傳把最外層 Context 拿掉後裡面的東西

像上圖,很常時候我們為了避免 Side Effect 例如 Math.random()console.log ,會先把他們丟到一個 Box 裡,但這樣做完運算會回傳 nesting 的 Box (也就是 Box 會包在另一個 Box,可以看下圖比較好懂),這樣導致後面運算變複雜,所以才會有這個方法,讓他 un-nest 扁平化,變成只要一層 Box 就好

同義詞還有 Joinbind(Haskell) 的說法但我個人比較喜歡 flatMap 較符合方法實際在做的事。

https://ithelp.ithome.com.tw/upload/images/20200925/20106426lbbrfW5Dv3.jpg

const Box = f => ({
    flatMap: x =>  f(x)
}

若我們把前一篇提過的 runEffect 也放進來。

const Box = f => ({
    flatMap: x =>  f(x),
    runEffect: x=> f(x)
}

恩?你可以會有疑惑說 runEffectflatMap 不是一模一樣嗎?
沒錯,當然你可以只用一個就好,但 runEffect 顧名思義我們都拿來執行 Effect 檢視內容。但若我們只是想要扁平化,除掉 nest 而已,並沒有想導致 Side Effect 但卻用 runEffect 這個名稱似乎有點怪,所以還是建議分開寫成兩個方法

Chain

map + flatMap

程式寫到最後會發現不斷再 .map().flatMap() 那不如直接寫一個快速方法是包含這兩個方法的
https://ithelp.ithome.com.tw/upload/images/20200925/20106426VmWvB09n00.jpg

const Box = f => ({
    map: g => Effect( x => g(f(x)) ),
    flatMap: x =>  f(x),
    chain: g =>  Effect(f).map(g).flatMap()
}

下一篇會實際用程式解說以上方法


如有錯誤或需要改進的地方,拜託跟我說。
我會以最快速度修改,感謝您

歡迎追蹤我的部落格,除了技術文也會分享一些在矽谷工作的甘苦。


上一篇
Functor 3: 程式碼解說篇
下一篇
Functor 5: 用 Effect functor 解決真實世界的 Side Effect
系列文
Functional Programming in JS30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
iT邦新手 2 級 ‧ 2022-04-17 12:33:59
const Box = f => ({
    map: g => Effect( x => g(f(x)) ),
    flatMap: x =>  f(x),
    chain: g =>  Effect(f).map(g).flatMap()
}

嗨~ 這邊的範例看起來有點怪怪的

  1. Box 跟 Effect 命名似乎沒有統一
  2. chain 似乎配對不太對

不知改成這樣對不對:

const Box = f => ({
    map: g => Box( x => g(f(x)) ),
    flatMap: x =>  f(x),
    chain: g =>  Box(f).map(g.flatMap)
}
iT邦新手 2 級 ‧ 2022-04-17 14:42:07 檢舉

第二點看了下一篇例子大概知道問題在哪。
原本還以為 chain 是直接把兩個 Box 連在一起

const a = Box((x) => x + 1)
const b = Box((x) => x * 10)

const c = a.chain(b)

結果是如下,則原本的 g => Box(f).map(g).flatMap() 就對了。

const a = (x) => x + 1
const b = (x) => Box.of(x * 10)

const c = Box.of(4).map(a).chain(b)

我要留言

立即登入留言