「隱藏運算」 是我發明的詞,它的正式名稱是 「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
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
裡面,而 maybe 是由 maybebuilder 生成的,顯然,關鍵在於 maybebuilder 的定義:
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!
, 因此可以預見一旦遇到 none, 後續的 f 就一律不會被運算,最終結果返回 none。如果是 some 則從 some 中提出取 a:int 並執行 f(a), 因此,經過這個背後的處理,表面上的a |> divideby y
就不會出錯了。
由於標準庫里也帶了一些好用的函式,比如 option.bind, 因此 maybebuilder 也可以改寫成:
type maybebuilder() =
member this.bind(x, f) = option.bind f x
member this.return(x) = some x
F 程式設計 函式式程式設計之Records
當你想把資料組成乙個結構化的格式,而不需要太複雜的語法時,你可以使用f 中的record型別。record型別與c語言的struct型別基本一樣,儲存一組型別的值,通過欄位的值來獲取。定義乙個record型別很簡單,只需要在大括號內定義系列的名稱 型別就可以。要例項化乙個record,只需要提供對應...
函式式程式設計之 初窺F
大量講解函式式程式語言的書籍最終都會用fuctor,monad,monoids,範疇論等各種詞彙嚇退命令式語言玩家,所以我試圖避開這些問題,揭開這些複雜詞彙帶來的具有實戰意義的成果。另外我會盡量使用c 語言來描述函式式程式設計思想,因為c 某些語法和特性來自於函式式語言的啟發,但c 終究並不是正統的...
F 函式式程式設計之 面向鐵道程式設計
原文 參考 不長,先看 吧,我在 後面寫講解。type request let validatename request match request with when name error name must not be blank ok request let validateemail fu...