Functional Programming 筆記


Posted by JingTeng on 2021-04-02

subtitle: Ken 與 FP 的旅程 ~ 2021-03-31

前言

一直以來都是對 procedure programming 和 OOP 比較熟悉,粗略地知道 functional programming 的概念,也有使用這樣的程式設計法,但沒有再進一步了解,機緣下聽到了 Ken 的這場分享,以下是我聽完分享後的一些思考。

先來一段情境

(pipe)

賣場上有三種折價券:98 折、95 折、92 折,沒有限制,可以同時使用。

如果用程式表達這三種折價券可以用三個函式:

const useCoupon98 = x => x*0.98;
const useCoupon95 = x => x*0.95;
const useCoupon92 = x => x*0.92;

如果用 procedure programming 描述我用三張折價券買了一本書:

let book = 400;
let result = useCoupon98(book)
result = useCoupon95(book)
result = useCoupon92(book)

好像也沒有不對,但在這個情境裡,也許用 functional 的方法思考會更符合情境。因為折扣卷並沒有一定要先使用哪一張,但這樣的寫法默默地寫下了執行順序。

如果使用 functional prgramming,似乎會好一點:

let book = 400;
let useCoupons = (a,b,c) => x => a(b(c(x))); //為方便使用固定三個參數,可以改成不定參數
let useCoupons(useCoupon98,useCoupon95,useCoupon92)(book)

雖然這個 useCoupons 並不完美,它裡面的實作依舊是按照順序呼叫,但這個函式已經成功將使用折價券的過程封裝起來,對使用者來說只知道它可以接收折價券當參數。

所以第一種寫法不好嗎?

還記得剛開始學習函式時,學到使用函式可以減少重複的程式碼,讓程式碼更好維護。
另外,也能透過函式命名讓程式更好懂(封裝流程?)。

再來換個情境看看,現在要做一顆切換顏色的按鈕。

範例示範用原生 js 與一步一步將一顆按鈕掛進 container,與用 React hook 方法的差別

const container = document.getElementById('container')
const btn = document.createElement('button')
btn.className ="gray"
btn.onClick = function(e){
    if(this.classList.conatins('gray')){
       this.classList.remove('gray')
       this.classList.add('red')
   }else{
       this.classList.remove('red')
       this.classList.add('gray')
   }
}
container.appendChild(btn)

如果用流程的方式思考:

  1. 我們必須先創造出一顆按鈕,才能加上 class。
  2. 判斷狀態時必須先判斷是灰色才能改成紅色

如果有很多顆按鈕就不好維護這段判斷顏色的程式了,於是想把這段程式抽給函式也很合理:

const changeColor = (prevColor, activeColor) => {
    if(this.classList.conatins(prevColor)){
       this.classList.remove(prevColor)
       this.classList.add(activeColor)
   }else{
       this.classList.remove(prevColor)
       this.classList.add(activeColor)
   }
}

順便再加個變數。
很基本,所有學到函式與變數的人都能輕鬆做到。

const container = document.getElementById('container')
const btn = document.createElement('button')
btn.className ="gray"
btn.onClick = function(e){
    changeColor('gray','red')
}
container.appendChild(btn)

現在,可以來看看 React 在做的事,其實也就是把整個過程要用到的命令式寫法,都抽成函式。

const Container = (props) => {
    const [color, setColor] = useState('gray')
    const changeColor = () => {
        setColor( prevColor => prevColor === 'gray' ? 'red' : 'gray')
    }

    return (
        <button className="${color}" onClick={changeColor} >click</button>
    )
}

抽出函式這件事從很久以前就學過了,但以往是有大量重複的地方或流程很長才會想到用函式。
但 functional programming 的思考,似乎是沒有必要的命令(沒有順序分枝?)都應該抽成函式。

procedure 的方式,在控制流程分枝時相當好用。
但 if ... else ... 遇到狀態時,就相當棘手了。
在不需要流程控制時,應該以 functional programming 思考。functional progamming 會在前端流行起來,也許是做前端需要大量維護狀態。

大概吧。

有空再研究ㄌ

參考


#程式設計







Related Posts

謂詞邏輯(Predicate Logic)

謂詞邏輯(Predicate Logic)

API

API

模組化與 Library

模組化與 Library


Comments