深入淺出 F# 之 Unit 與 Ignore
F# 是 FP,強調 function 都要有 input 值,也要有 return 值,若 function 真的沒有 input 值,也沒有 return 值,在 F# 該如何表示呢?
Version
macOS High Sierra 10.13.3
.NET Core SDK 2.1.101
Rider 2017.3.1
F# 4.1
Unit 與 ()
FP 的思考來自於數學函數,認為 function 都要有 定義域 與 對應域,如 y = f(x),也就是 input x 的型別就是 定義域,而 return y 的型別就是 對應域。
但在電腦語言的 function,可能沒有 input 值,也可能沒有 return 值,這就與數學 function 不同,針對這種需求,F# 特別設計出新的型別 unit,其值只有一個 ()。
無 return
1 | let print msg = printfn "%s" msg |
print() 為 function,其內容只有 printfn() 印出 msg,這就是典型 I/O 類的 side effect,但沒有 return 值。

若觀察 print() 的型別,其為 string -> unit ,也就是若沒 return 值,Type Inference 會推導為 unit。
Q : 所以
unit不就 C# 的void?
若以無 return 值的 function 觀點,unit 相當於 void 沒錯,但 unit 還有其他用途。
無 input
若想要建立 input() ,但不用傳入任何值,就可以印出 Hello World。
直覺會這樣寫:
1 | let print = printfn "%s" "Hello World" |
但別忘了 F# 強調是 Function Value,也就是 function 也視為是一種 value,因此都使用 let 。

Type Inference 推導為 unit,是 unit 型別的 value,而不是 function。
1 | let print () = printfn "%s" "Hello World" |
正確寫法應該使用 () 代表其無 input 值,但其 定義域 為 () ,也就是 unit type。

Type Inference 推導的 print 為 unit -> unit,是 unit -> unit 型別的 function,而不是 value。
1 | let print () = printfn "%s" "Hello World" |
呼叫 prinf() 時,也要明確傳入 () 代表 no input。

有 return 但不想用
1 | let sum x y = x + y |
明明 sum() 有 return x + y,但呼叫 sum() 時卻沒處理 return 值,compiler 編譯後會抱怨。

有兩種解法:
1 | let sum x y = x + y |
明確將 sum() 結果 binding 到 result value,這是 FP 最標準做法。
1 | let sum x y = x + y |
將 sum() 結果 pipeline 到 ignore(),則 compiler 就不會抱怨。
實務上若真的不想處理 function 的結果,建議使用
ignore()
Conclusion
- FP 嚴格遵守數學 function 定義,但電腦 function 卻可能沒有 input 也沒有 return,因此 F# 特別設計出
unit與(),這樣就與數學的定義域與對應域的觀念相通
Reference
Microsoft Docs, Unit Type
Jose Gonzales, What’s the Unit Type in F#?
Stack overflow, What does this () notation mean?
Chris Smith, Pramming F# 3.0 2nd