# Functional Programming 都可以當你阿公了 Part 1
###### tags: `fp`
https://www.canva.com/design/DAFQZltPNMM/ubTumTENVer8UFyt690EnQ/view?utm_content=DAFQZltPNMM&utm_campaign=designshare&utm_medium=link2&utm_source=sharebutton
在進入到正題之前,
我們要先來學習幾個概念。
> 以下範例雖然用數學作為例子,
> 但並不表示你必須要很了解數學才能看懂,
> 這裡意在表示**無關使用何種程式語言**。
## 封裝
我們可以舉一個國中數學公式作為例子,
```math
c = \sqrt{a^{2}+b^{2}}
```
如果對以上的公式不太熟悉的人也沒關係喔,
你只要知道,這個公式可以用來計算 **三角形的斜邊長** 。
如何使用這個公式呢?
我們只需要把 a 跟 b 替換成 實際的數值,
而他的運算結果就會是 三角形的斜邊長。
對於一般民眾來說,
我們其實不需要知道這段公式為什麼可以計算出斜邊長吧。
發現且證明這段公式可行,那個是數學家的工作,
而我們需要做的僅只是 用它來完成我們的工作。
而像這種不需要了解其細節,
我只要給它需要的參數,他就會給我相對應的結果,
這個在軟體工程裡就被稱之為 **封裝**。
## 抽象
我們先來看看,最簡單使用這個公式的情況:
```math
\sqrt{ 3^{2} + 4^{2} } = 5
```
如果只有簡單一行的話,
我們確實可以很快的理解這段公式的 **目的** 是什麼吧。
那來嘗試看看下面的公式:
```math
\sqrt{ (x1 - p1)^{2} + (y1 - p2)^{2} } +
\sqrt{ (x2 - p1)^{2} + (y2 - p2)^{2} } =
\sqrt{ (x2 - x1)^{2} + (y2 - y1)^{2} }
```
請問上面公式的用途是什麼?
如果你沒辦法在幾秒之內看出他的用途,
沒關係,我也做不到。
我相信一般的大眾,
是做不到一眼就看出,這是用來檢測某個點是否在某條直線上的公式。
而且如果可以,我其實也不太想每天看到這種東西,太痛苦了吧。
如果這裡,可以用一般人能理解的語言給他一個名字,
那我是否可以更容易理解這個公式的用途,
而不需要去猜測。
讓我們來試試看另一種方式:
```math
CheckPointOnLine:
\sqrt{ (x1 - p1)^{2} + (y1 - p2)^{2} } +
\sqrt{ (x2 - p1)^{2} + (y2 - p2)^{2} } =
\sqrt{ (x2 - x1)^{2} + (y2 - y1)^{2} }
```
並且我們可以透過名字下去描述
我們在做運算的時候,
就不需要每次都看到一坨運算式。
```math
CheckPointOnLine(x1, y1, x2, y2, p1, p2)
```
透過使用名字來代替其實際的細節,
能達到同樣的效果且能夠輕易的被任何人理解意圖,
也能透過名字與他人進行溝通。
這個行為稱之為**抽象化**,
這是身為人類必然會出現的能力。
## 純粹
你知道在紐約中午十二點的時候是 `1 + 1 = 3` 而不是 `2` 嗎?
當然以上唬爛你的。
不過假設這件事情是真的,那會是多麽可怕的情況,
每個在紐約生活的人,戶頭會瞬間多出 1.5 倍,
年齡從 20 歲瞬間老了 10 歲,
所有的系統都要重寫。
所以
```math
1 + 1 = 2
```
這個運算的結果,**必須**,
1. 不受外界變化而改變。
2. 不應改變外界情況。
基於同樣的概念,
如果一段程式只會根據它被給予的參數而改變其結果的話,
那我們其實就可以簡單的從使用的參數跟函式去推斷結果,
也不會因為調用這個程式而有任何的 **副作用**。
我們可以建構出更加穩定且安全的程式,
而不用擔心他會因為 *時間*, *地點*, *溫度* ... 之類外在的系統而變化,
也不用擔心使用他會影響到外界。
你給程式一個原始資料,他就會給你一個相對應的結果,
而如果你之後再給他相同的資料,
那他應該還是要給你相同的結果。
這個結果不會因為外界的改變,而有所變化,
也不會因為你調用的次數不同,而有所變化。
我們來看幾個例子:
> 以下用 JS 作為範例
```javascript
const array = [1, 2, 3]
function addElementIntoArray(element) {
array.push(element)
}
addElementIntoArray(4)
console.log(array) // === [1, 2, 3, 4]
```
以上的程式,在語法上是正確的,
但個人覺得並不是一段好的程式。
來看以下情況
```javascript
const array = [1, 2, 3]
function addElementIntoArray(element) {
array.push(element)
}
function doSomethingElse() {
if (Date.now() % 2 === 0) {
array.pop()
}
}
addElementIntoArray(4)
doSomethingElse();
console.log(array)
```
現在請問你能判斷 `array` 會印出什麼嗎?
顯然不行吧。
我們無法斷定 `doSomethingElse` 會不會異動到 `array`。
但如果我們改用以下做法:
```javascript
const array = [1, 2, 3]
function addElementIntoArray(arr, element) {
return [...arr, element]
}
function doSomethingElse() {
if (Date.now() % 2 === 0) {
array.pop()
}
}
const new_array = addElementIntoArray(arr, 4)
doSomethingElse();
console.log(new_array) // [1, 2, 3, 4]
```
無論 `doSomethingElse` 執行了幾次,
都不會影響到 `addElementIntoArray` 的結果。
所以對我來說 `addElementIntoArray` 就是一段好的程式,
因為它很穩定,我們可以輕易的從他的參數,推斷出他的結果。
## 所以 Functional Programming
對我來說,FP 就是這樣的一種思考風格。
1. 抽象化:用容易理解的表達方式取代實作細節。
2. 可推導:程式必須純粹,相同輸入就會得到相應的結果。
3. 穩定:程式不受外界的變化而影響到結果。
從這樣的基本思路,逐漸發展成與 OOP 不同的解決問題方式。