日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

重新理解 Monad

發(fā)布時(shí)間:2025/7/14 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 重新理解 Monad 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

對(duì)于大多數(shù)剛剛?cè)腴T函數(shù)式編程的同學(xué)來說,monad(單子、又叫單體)可能是這里面的一道坎。你可能對(duì) map 、 flatMap 以及 filter 再熟悉不過,可是到了高階的抽象層次上就又會(huì)變得一臉懵逼。其實(shí)每個(gè)人在學(xué)習(xí)的階段都會(huì)經(jīng)歷這個(gè)過程,不過希望這篇文章能讓你重新理解 monad 以及其他相關(guān)的概念。

Optional

Swift 作為一門類型安全的強(qiáng)類型語言,它在編譯階段就會(huì)對(duì)你的數(shù)據(jù)類型進(jìn)行比較多的檢查。因此,在 Swift 中我們遇到了一種新的數(shù)據(jù)類型,叫做?Optional?。它的定義如下:

Optional 是個(gè)枚舉類型,可以看到它有兩個(gè)值: none 以及 some 。簡單點(diǎn)講:

值要么存在(presence),要么不存在(absence)。

這也就意味著 Optional 可能是包含了一個(gè)某個(gè)類型的值( some ),也可能是什么都沒有( none )。在這里,Optional 就是個(gè)容器( container )。

對(duì)于基礎(chǔ)類型,在其后面直接加上 ? 就代表了這就是個(gè)可選值類型(Optional value)。默認(rèn)值即為 Optional 的預(yù)設(shè)值 nil (區(qū)別于 Objective-C)。

判斷一個(gè)可選值是否為空,我們通常會(huì)采用 if let 的寫法來解包(wrap an optional)。

Map

基礎(chǔ)類型的 map 函數(shù)調(diào)用是非常簡單的:

如果對(duì)于 Optional 呢?

我們發(fā)現(xiàn), map 函數(shù)作用在 Optional 上時(shí):

  • 值存在( .some ):值類型 Optional(Int) ,返回值類型 Optional(Int) ;
  • 值不存在( .none ):返回值等同輸入( nil )。

map 函數(shù)定義在 Optional 上,最大的好處就在于空值( nil )的處理,不需要我們再去使用 if let 解包(空值并沒有乘法運(yùn)算):

因此:

map 只對(duì)值存在的可選值進(jìn)行處理。

map 通常的表示方法:

在這里,容器 Container 就相當(dāng)于 Optional ,泛型 T 和 U 均為 Int 類型。在處理完 Int 值后 map 函數(shù)就把 Int 型轉(zhuǎn)換成了 Optional(Int) ,并返回。

Async Callback Trouble

處理異步的網(wǎng)絡(luò)請(qǐng)求是一件痛苦的事情。你一定碰到過:

為什么我的異步回調(diào)就沒有一種方式能夠告訴我在哪里出錯(cuò)了呢?方案其實(shí)也很簡單,我們先在定義一下異步處理的結(jié)果( Result ):

有沒有發(fā)現(xiàn) Result 類型很像 Optional ?沒錯(cuò)。它能包含一個(gè)成功的返回值;也能在沒有返回值時(shí)提供一個(gè)錯(cuò)誤消息。

我們也同時(shí)希望 map 能幫我們處理 Result :如果有結(jié)果,就從 JSON 轉(zhuǎn)換到 String 、再轉(zhuǎn)換到其他類型;否則返回錯(cuò)誤信息。

這樣的 map 函數(shù)怎么寫呢?不妨先來看一下:

舉個(gè)最基本的例子,我們希望將返回的 JSON 轉(zhuǎn)換成 String ,那在這里, map 所接受的高階變換 f 就是一個(gè) JSON -> String 的函數(shù)。調(diào)用時(shí), Result<JSON> 就會(huì)通過 map 最終轉(zhuǎn)換成 Result<String> 類型。

看上去很不錯(cuò)!

Functor

在了解 monad 之前,我們先來了解一下它的孿生兄弟:functor(函子)。

從上面的例子中可以看到,在調(diào)用 map 函數(shù)后,我們還會(huì)把 String 類型的結(jié)果封裝成了一個(gè)可選值 Result<String> 。

像這樣能夠從容器(Container,這里即 Result )中取出元素,并通過某個(gè)函數(shù)將其轉(zhuǎn)換成可以再次被容器包裝的結(jié)果的類型就稱之為 functor。

還有些不懂?沒事,暫時(shí)就先記住有 functor 這么個(gè)玩意兒。

FlatMap

重新回到之前 JSON -> String 的例子上來。假設(shè)我們已經(jīng)將某個(gè) json 轉(zhuǎn)換成了字符串,現(xiàn)在需要將字符串重新格式化,那我們應(yīng)該需要再調(diào)用一次 map :

不過我們多么希望返回的結(jié)果是個(gè) Result<String> 的類型。不如寫一個(gè)函數(shù)來解包帶有兩層的 Result<T> 。

還有一點(diǎn),在寫 flatten 函數(shù)的時(shí)候,我們也同時(shí)考慮了在 map 函數(shù)中出現(xiàn)轉(zhuǎn)換失敗的問題。轉(zhuǎn)換正確的時(shí)候的確我們的 map 的輸出是個(gè) String 類型的值,隨之輸出 Result<String> 進(jìn)入下一層的 map ;如果失敗,則應(yīng)當(dāng)是被轉(zhuǎn)換成 .failure 的結(jié)果。

將 map 和 flatten 結(jié)合一下,我們就得到了所謂的 flatMap (又稱作 bind ):

通過 flatMap 我們可以非常輕松地處理中途出現(xiàn)的錯(cuò)誤異常,并對(duì)給定類型進(jìn)行多次連續(xù)的類型轉(zhuǎn)換。

Monad

最后再來說什么是 monad。Chris Edihof 曾在他的文章中指出:

如果可以為某個(gè)類型定義它的 flatMap 方法,那么這個(gè)類型通常就是個(gè) monad 。(If you can define flatMap for a type, the type is often called a monad .)

在這里,我們通過 map 和 flatten 實(shí)現(xiàn)了 Result 類型的 flatMap 。此時(shí),我們就可以說 Result 這個(gè)類型就是一個(gè) monad。

Deal with Monad

到現(xiàn)在你就可以非常輕松地處理你的異步請(qǐng)求了。

Summary

  • 重新回顧一下 map 和 flatMap 在 Result<T> 上的工作方式:

  • Functor、monad 可以看作是一種運(yùn)算的抽象。它們的目的都是為了更好的解決類型的封裝和轉(zhuǎn)換。

Further Reading

  • ReactiveCocoa

  • Promise & Future

  • Swift 中的 throw 及 rethrow

References

  • Functor and Monad in Swift - Javier Soto
  • Swift 燒腦體操(五)- Monad - 唐巧
  • Monads Everywhere: Porting C#’s Tasks to Swift - Nevyn Bengtsson
  • Monads in Swift - Chris Edihof
  • 続?ゲンバのSwift
  • ?

    來自:http://blog.cee.moe/recap-monad.html

    http://www.open-open.com/lib/view/open1478588965804.html

    總結(jié)

    以上是生活随笔為你收集整理的重新理解 Monad的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。