iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 21
1
Software Development

Functional Programming in JS系列 第 21

Functor 2: 圖解 Box Data Type

https://ithelp.ithome.com.tw/upload/images/20200921/20106426WZmSynR8aa.jpg

"The combination of calling map and the box tab type would lead we call functor"

上一篇 Functor 1 ,提過這種盒子 context (shape) 裡裝著值 Value ,並滿足 can be map over 特性也是 Functor, 這一篇就會來好好探究這種 Data Type 的 Functor。這種 Data Type 的好處就是不止是單純的值,還包括相關的屬性跟方法。

Note. 接下來一系列的圖都是參考經典圖 Aditya Bhargava 然後為了加深印象再自己用 Canva 畫的。


What's Box?

先從我們最熟悉的基本值 Value 開始說

https://ithelp.ithome.com.tw/upload/images/20200921/20106426tTIn69XIGZ.jpg

我們都知道如何處理值跟值之間運算,可以寫一個 function 輸入一個值 (input) 然後得到另一個值 (output)

https://ithelp.ithome.com.tw/upload/images/20200921/20106426MpNAZCPpD2.jpg

const add = x => x + 3;
add(2); // 5

但若包成 Box

https://ithelp.ithome.com.tw/upload/images/20200921/20106426WZmSynR8aa.jpg

原來的 function 就不能用了,因為 + 3 這個涵式是給基本值用的

https://ithelp.ithome.com.tw/upload/images/20200921/20106426PNewAl3nsY.jpg

我們需要重新定義一種神奇的運算 map 能接受 Functor 當作輸入參數

https://ithelp.ithome.com.tw/upload/images/20200921/20106426Yp5k27IWjx.jpg

const Box = x => ({
  map: f => Box(f(x)), // 神奇的運算在此
  fold: f => f(x), // 取值 remove from the box
});

const result = Box(2)
  .map(x => x + 3) // Box(5)

https://ithelp.ithome.com.tw/upload/images/20200921/20106426gNXmkC9FUF.jpg

map 內部,實際上是這樣運作的: 取出值,用 function 處理過後再裝回 Context 裡

const Box = x => ({
  map: f => Box(f(x)),
  fold: f => f(x), // 取值 remove from the box
})
const result = Box(2)
  .fold(x => x + 3) // 5

Why use Functor?

JS 本質仍不是一個 FP 語言,所以應用到了 Functor 的概念我只能盡量解釋,主要目的就是他可以讓 Value 維持在 Box 裡面,但仍然可以擁有一些 State 跟 method (像 OOP 的 class)。這樣讓 Box 自己運用函式也可以達成抽象化,我們並不是直接呼叫函式,而是說

Hey Box, call that function to me

這不就是 FP 概念嗎

那你可能會覺得那幹嘛不用 Class 就好,再說一次並沒有哪種寫法是絕對完美,只是了解以後多一種選擇而已。同一個問題你可以用數十種方式方式達成目的,但用 Box 好處是你不用去管理 State 的狀態,例如

/**
@parm {value} x
*/
const Box = x => ({
  map: f => Box(f(x)),
  value: x // 只是容易看值用而已
})

Box('a')
.map(x => x.toUpperCase())
.value;  //'A'

x => x.toUpperCase()x 在這邊用完之後就會完全消失,你不用煩惱現在 x 到底是多少,但 Class 的狀態會是一直存在的,需要去記憶他現在到底是多少。

另一個好處 input 的型別就算不同,但方法也可以共享,例如 input 是 String 但想用 Arraymap

// input 為 Array 寫法
['a']
.map(x => x.toUpperCase())

// ['A']
/**
@parm {value} x
*/
const Box = x => ({
  map: f => Box(f(x)),
  value: x // 只是容易看值用而已
})

Box('a')
.map(x => x.toUpperCase())
.value;  //'A'

map 看起來像 recursive,但其實不是,他只是把運算過的值放回 Box 而已。


參考文章

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

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


上一篇
Functor 1: 概念篇
下一篇
Applicative
系列文
Functional Programming in JS30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言