爲什麼單聲道不是monad是一個應用程序,而application是一個functor。你在網絡上的許多文章中看到這個繼承鏈(我經歷過)。但是,當遊戲者和應用者撰寫Monad爲什麼打破這個?monad爲什麼不在scala中編寫
有人可以在scala中提供一個簡單的例子來演示這個問題嗎?我知道這個問題很多,但沒有一個簡單的例子就很難理解。
爲什麼單聲道不是monad是一個應用程序,而application是一個functor。你在網絡上的許多文章中看到這個繼承鏈(我經歷過)。但是,當遊戲者和應用者撰寫Monad爲什麼打破這個?monad爲什麼不在scala中編寫
有人可以在scala中提供一個簡單的例子來演示這個問題嗎?我知道這個問題很多,但沒有一個簡單的例子就很難理解。
首先,我們從一個簡單的問題開始。比方說,我們需要得到兩個整數的總和,這兩個整數都包含在Future
和Option
中。我們假設,我們使用cats
庫。
如果我們用單子辦法(又名flatMap
),我們需要:
Future
和Option
應該對他們定義Monad
實例OptionT
將只能用於Option
(精確地F[Option[T]]
)所以,這裏是代碼(讓我們忘記理解和提升使其更簡單):
val fa = OptionT[Future, Int](Future(Some(1)))
val fb = OptionT[Future, Int](Future(Some(2)))
fa.flatMap(a => fb.map(b => a + b)) //note that a and b are already Int's not Future's
如果你看看OptionT.flatMap
來源:
def flatMap[B](f: A => OptionT[F, B])(implicit F: Monad[F]): OptionT[F, B] =
flatMapF(a => f(a).value)
def flatMapF[B](f: A => F[Option[B]])(implicit F: Monad[F]): OptionT[F, B] =
OptionT(F.flatMap(value)(_.fold(F.pure[Option[B]](None))(f)))
你會發現,代碼是相當具體到Option
的內在邏輯和結構(fold
,None
)。同樣的問題對於EitherT
,StateT
等
重要的是,有沒有貓定義FutureT
,這樣你就可以撰寫Future[Option[T]]
,但不能做到這一點與Option[Future[T]]
(以後我會告訴這個問題甚至更通用)。
在另一方面,如果你選擇使用Applicative
組成,你必須滿足只有一個要求:
Future
和Option
應該有Applicative
情況下對他們定義你不需要任何特殊的變形器Option
,基本上貓圖書館提供Nested
類適用於任何Applicative
(讓我們忘記適用建設者的糖來簡化理解):
val fa = Nested[Future, Option, Int](Future(Some(1)))
val fb = Nested[Future, Option, Int](Future(Some(1)))
fa.map(x => (y: Int) => y + x).ap(fb)
讓我們交換他們:
val fa = Nested[Option, Future, Int](Some(Future(1)))
val fb = Nested[Option, Future, Int](Some(Future(1)))
fa.map(x => (y: Int) => y + x).ap(fb)
作品!
所以,是的單子是應用型,Option[Future[T]]
仍然是一個單子(上Future[T]
但不能在T
本身),但它可以讓你只操作Future[T]
不T
。爲了「合併」Option
和Future
層 - 您必須定義一元變換器FutureT
,爲了合併Future
和Option
- 您必須定義OptionT
。並且,OptionT
在cats/scalaz中定義,但不是FutureT
。
一般(從here):
不幸的是,我們真正的目標,單子組成,是相當多 困難。實際上,我們實際上可以證明,從某種意義上說, 沒有辦法構造一個上述類型的連接函數,只能使用兩個monad的操作(參見附錄中關於大綱 的證明)。由此可見,我們可能希望只有這樣,才能形成 的組成是,如果有連接 雙組份
一些額外的結構和該組合物中甚至沒有可交換的,因爲我已經顯示了Option
和Future
。
作爲練習,你可以嘗試定義FutureT
的flatMap:
def flatMapF[B](f: A => F[Future[B]])(implicit F: Monad[F]): FutureT[F, B] =
FutureT(F.flatMap(value){ x: Future[A] =>
val r: Future[F[Future[B]] = x.map(f)
//you have to return F[Future[B]] here using only f and F.pure,
//where F can be List, Option whatever
})
基本符合這樣的實現問題是,你必須從r這是不可能在這裏‘提取’的價值,假設你可以不提取Future
的值(沒有定義它的comonad),如果我們正在討論「非阻塞」的API,這是真的。這基本上意味着你不能「交換」Future
和F
,就像Future[F[Future[B]] => F[Future[Future[B]
那樣是自然變換(仿函數之間的態射)。這樣解釋了this general answer第一個註釋:
您可以撰寫單子,如果你能提供一個自然轉化交換:納米 - >明尼蘇達州一個
Applicative
小號但是沒有這樣的問題 - 你可以很容易地編寫它們,但請記住,兩個Applicatives
的組合結果可能不是單子(但將永遠是一個應用)。 Nested[Future, Option, T]
不是T
上的monad,無論是Option
還是Future
都是T
上的monad。用簡單的詞彙Nested as a class沒有flatMap
。
這將是也有利於閱讀:
全部放在一起(F
和G
是單子)
F[G[T]]
是G[T]
一個單子,但不是在T
G_TRANSFORMER[F, T]
爲了從F[G[T]]
得到T
單子需要。MEGA_TRANSFORMER[G, F, T]
因此變壓器不能建立在單子上面 - 它需要G
定義的附加操作(好像在G
comonad應該足夠)G
和F
)被但不是每一個應用都是單粒子F[G[T]]
適用於G[T]
和T
。然而,斯卡拉需要創建NESTED[F, G, T]
爲了得到T
(它是在貓庫中實現)組成應用。NESTED[F, G, T]
是合用的,但沒有一個單子這意味着你可以撰寫Future x Option
(又名Option[Future[T]]
)到一個單一的單子,但你不能在不知道撰寫Option x Future
(又名Future[Option[T]]
),他們是什麼除了單子之外。你可以將任何兩個應用程序組合成一個應用程序,你也可以將任意兩個monad組合成一個單一的應用程序(但不是一個單一的monad)。
託尼莫里斯就單子變壓器進行了一次演講,這很好地解釋了這個準確的問題。
http://tonymorris.github.io/blog/posts/monad-transformers/
他用哈斯克爾,但實例容易翻譯到階。
可能的重複[Applicatives撰寫,單子不要](http://stackoverflow.com/questions/7040844/applicatives-compose-monads-dont) – ziggystar
這是haskell答案不適用於scala – Jay
檢查出[答案由Conal](http://stackoverflow.com/a/7070339/108915)。它是語言不可知的。 Monad是一個數學概念,它們在語言之間沒有區別。 – ziggystar