F# 函數語言程式設計之 - 隱藏運算
阿新 • • 發佈:2020-12-13
“隱藏運算” 是我發明的詞,它的正式名稱是 “computation expressions”。
但 “computation expressions” 這個名稱實在讓人非常費解,也不能反映它的作用,不是一個好名稱。
它的作用是在背後對兩個表示式進行一些操作,讓表示式們表面上看起來簡單。
請看例子:
let divideBy bottom top = match bottom with | 0 -> None | _ -> Some <| top/bottom let maybe = new MaybeBuilder() let divideWorkflow init x y z = maybe { let! a = init |> divideBy x let! b = a |> divideBy y let! c = b |> divideBy z return c } divideWorkflow 12 3 2 1 // Some(2) divideWorkflow 12 3 0 1 // None
請看那幾個 let!
, 表面上是 init 除以 x, 得出結果 a 再除以 y, 以此類推。這個表面上的邏輯非常清晰,但如果不是背後隱藏了一些處理(意思是,如果用 let
而不是用 let!
),這個程式碼是跑不通的。因為 init 除以 x 得出來的 a 不是一個數字(divideBy 的返回值是 Option, 不是 int), 因此如果讓 a 直接除以 y 會產生型別不匹配的錯誤。
簡單來說,let!
表示 “computation expressions”, 也就是意味著在背後隱藏著一些我們表面上看不見的運算。
那麼,這個背後的運算具體是什麼?我們可以看到,全部 let!
都在 maybe{...}
type MaybeBuilder() =
member this.Bind(x, f) =
match x with
| None -> None
| Some a -> f a
member this.Return(x) = Some x
如上所示,這個 MaybeBuilder 的定義不是系統自帶的,要我們自己寫。可以看到,這個 “背後的程式碼” 對 x:Option 進行處理,如果是 None 則直接返回 None, 並且由於這個 None 會傳遞給下一個 let!
a |> divideBy y
就不會出錯了。
“computation expressions” 可以把囉嗦的輔助語句隱藏在背後,讓表面上的核心語句看起來很簡潔,因此很好用,是 F# 裡很常用的一種技術。但由於它是 “隱式的” 而不是 “顯示的”, 所以理解起來需要在腦子裡多繞幾個彎,本文只是簡單地介召了它的主要特點,想了解得更詳細請看以下資料: