函式
本章節包含必須熟悉的基本 Elm 語法:函式(functions),函式標記式(function signatures),部份套用(partial application)及輸送運算子(pipe operator)。
函式
Elm 支援兩種函式:
- 匿名函式(anonymous functions)
- 具名函式(named functions)
匿名函式
顧名思義,函式沒有名稱:
\x -> x + 1
\x y -> x + y
反斜線與箭頭之間為函式引數(arguments),箭頭右邊則是希望函式作的事情。
具名函式
Elm 具名函式看起來像是:
add1 : Int -> Int
add1 x =
x + 1
- 範例第一行為函式的標記式。雖然標記式是選擇性(optional)加入,但建議你加入。這會讓你的函式意圖更加清楚。
- 剩下的部份則是函式的實作。實作必須遵循標記式。
此例中標記式的描述:給定一個整數(Int)作為引數,傳回另一個整數。
呼叫方法:
add1 3
Elm 使用空白(而非括號)來表示函式套用
下面是另一個具名函式:
add : Int -> Int -> Int
add x y =
x + y
函式取用兩個引數(皆為 Int)並傳回另一個 Int。呼叫函式如下:
add 2 3
無引數
無引數的函式在 Elm 中是一個常數:
name =
"Sam"
如何套用函式
前述取用兩個引數的函式像是:
divide : Float -> Float -> Float
divide x y =
x / y
我們可以想像這個函式標記式,取用兩個浮點數引數,傳回另一個浮點數:
divide 5 2 == 2.5
然而,這並不完全正確,Elm 中所有函式都只取得一個引數,傳回一個結果。而結果可以是另一個函式。 以上述的函式解釋。
-- 當我們用:
divide 5 2
-- 評估成:
((divide 5) 2)
-- 首先,評估 `divide 5`。
-- 引數 `5` 套用到 `divide`,傳回一個中間函式。
divide 5 -- -> 中間函式
-- 讓我們稱這個中間函式為 `divide5`。
-- 如果看得到中間函式的標記式及內容,那看起來就像是:
divide5 : Float -> Float
divide5 y =
5 / y
-- 所以有個函式已經套用了 `5`。
-- 接著套用下一個引數,例如 `2`
divide5 2
-- 這傳回最後結果
這裡不需撰寫括號的原因是,套用函式是從左開始結合。
分組括號(Grouping)
當需要呼叫某個函式,其引數值係來自另一個函式的結果,這就需要括號來分組呼叫:
add 1 (divide 12 3)
divide 12 3
傳回的結果作為 add
的第二個引數。
相較之下,其他的語言可能寫成:
add(1, divide(12, 3))
部份套用(Partial application)
如上述說明,每個函式只取一個引數,傳回另一個函式或結果。
表示呼叫類似上述 add
函式帶入一個引數,如 add 2
,傳回的是部份套用的函式。
傳回的函式標記式為 Int -> Int
。
add 2
傳回另一個函式,其中值 2
綁定為第一個引數值。
呼叫傳回的函式並帶入第二個引數值,將傳回 2 +
第二個引數值的結果:
add2 = add 2
add2 3 -- 結果為 5
在 Elm 中部份套用非常有用,讓你的程式碼更好閱讀,並可在應用程式中的函式之間傳遞狀態(state)。
輸送運算子(The pipe operator)
如前述所示,你可以用成巢狀函式,像是:
add 1 (multiply 2 3)
這只是個微不足道的範例,考慮更複雜的範例:
sum (filter (isOver 100) (map getCost records))
這樣的程式碼難以閱讀,因為需要從內到外的解析。輸送運算子讓你撰寫出更好閱讀的程式碼:
3
|> multiply 2
|> add 1
這功能非常十分依賴先前提到的部份套用。這個範例中,3
這個值傳遞到部份套用函式 multiply 2
。接著,其結果值再傳遞到部份套用函式 add 1
。
若使用輸送運算子,上述複雜的範例可寫成:
records
|> map getCost
|> filter (isOver 100)
|> sum