最後兩天了,這兩天會帶大家用 functional programming 的視角來看 Kotlin,其實是偷偷的傳教(?)(希望沒有慘到勸退。作為首日,還是要跟大家介紹一下 functional programming。
Functional Programming (函數程式設計) 跟常見的 OOP (物件導向程式設計 - 如:Java, Kotlin) 或是 Imperative Programming (指令式程式設計 - 如:C ) 不同,通常須具備下列特性:
首先是 Pure Function,他也是涵式的一種,但限定必須具備給予相同輸入時 “必定" 返回相同輸出,也就是說,當今天這個涵式有呼叫外部服務 (例如:資料庫、網路回應服務等),那麼他就有可能因為各種因素 (比如:網路斷線資料漏接收) 導致輸出回應不相同;同理,如果這個函式依賴了某個全域變數,或是單例可變動資料,那麼相同的輸入也可能會得到不同輸出。
看到這裡,讀者們可能也猜想到下一項不可變性可以帶來的優勢了因為不可變性就間接保證輸出會與輸入成對相同,但 pure function 的優勢呢?不能讀取資料庫,也不能使用網路回應,那我這程式可以寫來做什麼,這些不是當今最大需求的部分嗎?
沒錯,因此在 functional programming 在現實上並沒有辦法達到純 pure function,但我們可以盡可能讓不 pure 的部分 (也就是 side effect) 在邊界發生,讓大部分的程式都是 pure 的,這樣不僅可以在輸入未選定下預測輸出,對於單元測試來說也是一大福音 (因為只要輸出入都一樣但測試失敗了就代表 code 改壞了 XD)。
但是不對啊,side effect 的部分呢?我們期望它發生在邊界,要怎麼做到?這時候就需要使用 functional programming functor 的 monad 了,這裡我們先想像把這些行為先用一個箱子裝起來,等等到我們真的要用的時候才會打開 (聽起來很像潘朵拉的盒子(X )。聽到這裡可能會有點混淆,我希望處理資料庫的回傳資料,但我又要在邊界發生,HOW TO?
這邊引入一種想法去理解,透過 higher-order function 我們可以把一系列的函式行為進行串接,這時候我們可以得到一個最終的咒語去達到我們的目的,咒語中可能有不同片段組成,在非 functional programming 情境下,我們會直接在片段中去訪問資料庫,這時候我們就會遇到往下傳遞的資料可能存在多中型態,透過 monad 我們可以暫時把這個訪問行為包起來晚點做,至於多晚,就是當咒語被唸出來的時候,我們再去訪問就好啦XD 這樣在撰寫程式過程中我都可以清楚知道這裡會有什麼型別的變數被傳遞了耶~