[Day05] Functor


老實說從這一節開始,就是一個我也很不確定的領域了(抖)。Functor、Applicative、Monad 這三者之間的關係可以說是 FP 中最曲折離奇的部分,難倒了許許多多的英雄好漢。不過我還是盡量在我所理解的範圍內跟大家說明這些名詞的概念,有錯的話還請多多包涵,願意跟我討論的話也是十分歡迎。
 
在我的認知中,Functor 是一種計算語境(computational context)(有讀者要抗議了:你怎麼拿一個看不懂的名詞去解釋另一個看不懂的名詞?)。我們可以把 Functor 當作包含上下文(context)的運算。
 
舉個最常見的例子:JavaScript 的 Promise。

注意!JS 的 Promise 並不是 Functor。
我們會在後續說明他為什麼不是 Functor,這裏只是要先說明 context 的概念。

我們知道 Promise 可以透過 then 接收一個 callback,計算的結果會被傳入 callback 執行。Promise 的建構子會執行一個函數,並且在失敗或成功時呼叫 resolve 或 reject。也就是說,then 的參數裡面的 callback 函數,有可能會收到成功或失敗的結果,而這個會失敗的可能性就是所謂的 context
 
前幾天很認真看的同學應該會發現,如果所有 data 都是 immutable,那理論上用這樣子寫出來的程式不應該會執行失敗,因為所有 symbol 的值都早在編譯時期就可以藉由綁定決定好了。
 
然而在有任何 I/O 發生時,就有可能會有失敗的情況,如使用者輸入不符合我們要的格式,或是 network I/O 斷線 ...... 等等。
 
Functor 的計算語境就是在指這種狀態。
 
以 Haskell 為例的話,在 Haskell 中有三種 data type(可以想像成 OOP 中的 class),分別是 Maybe、Just 跟 Nothing。 Maybe 的定義如下:

data Maybe a = Just a | Nothing


也就是說 Maybe a (a 為任意型態)只可能是 Just aNothing。我們可以把 Nothing 想像成類似 JS 的 null ,所以假設 JS 一個 Promise 的回傳值會固定有一種型別,例如一個 Promise resolve 成功時的結果型態會是 Int 的話,那我們就可以把這個 Promise 的回傳值型態當作是 Maybe Int,代表當他成功時值會是 Just Int,失敗時會是 Nothing(null),Maybe 隱含了運算(Promise)可能會失敗的 context。
 
Functor 還有一個特性是可以被 map-over ,也就是可以透過 fmap

fmap (a -> b) -> f a -> f b

去運算被包在 context 的值。用 Promise 想像的話就是,我們可以透過 then 的 callback 去運算 Promise 的結果。then callback 是一個普通、沒有包在 context 中的函數,卻可以作用在被包在 context 中的值 (Promise)之上,這就是 map over 的概念。
 

 
從這裏我們可以發現 Promise 借鏡了許多 Functor 的概念,然而他其實不滿足 Functor 的一些性質 (Associativity Law),可以參考這篇文章Are Promises Monads, Functor or Applicative
 
* 本文圖片來自這裏

#Functional Programming #程式語言
Functional Programming 到底是什麼?為什麼最近這麼夯? 這一系列的文章會探討幾個 FP 的特性,讓大家一起體驗 FP 的魔力。






Related Posts

Vue.js 學習旅程Mile 13 – List Rendering 列表渲染篇:v-for

Vue.js 學習旅程Mile 13 – List Rendering 列表渲染篇:v-for

Kotlin 練功場 - Android 組

Kotlin 練功場 - Android 組

當 React web app 遇上 Progressive web app

當 React web app 遇上 Progressive web app



Sponsored



Comments