簡體   English   中英

為什么monad不會在scala中構成

[英]Why do monads not compose in scala

當Monad是一個應用者而一個Applicative是一個Functor時,為什么monad不能編寫。 你在網上的許多文章中看到了這個繼承鏈(我已經經歷過)。 但是,當Functors和Applicatives組成為什么Monads打破了這個?

有人可以在scala中提供一個演示此問題的簡單示例嗎? 我知道這個問題很多,但沒有一個簡單的例子就很難理解。

首先,讓我們從一個簡單的問題開始。 比方說,我們需要得到兩個整數的總和,每個整數都包含在FutureOption 讓我們拿cats庫來使用Scala語法來模擬Haskell的標准庫定義。

如果我們使用monad方法(又名flatMap ),我們需要:

  • FutureOption都應該在它們上面定義Monad實例
  • 我們還需要OptionT變換器OptionT ,它只適用於Option (精確地為F[Option[T]]

所以,這里是代碼(讓我們忘記for-comprehension和提升以使其更簡單):

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的內部邏輯和結構( foldNone )。 EitherTStateT等同樣的問題

這里重要的是沒有在貓中定義FutureT ,所以你可以FutureT Future[Option[T]] ,但不能用Option[Future[T]]來做(后來我會證明這個問題是均勻的更通用的)。

另一方面,如果您使用Applicative選擇合成,則您只需要滿足一個要求:

  • FutureOption都應該有針對它們定義的Applicative實例

你不需要任何特殊的變換器用於Option ,基本上貓庫提供適用於任何Applicative Nested類(讓我們忘記應用構建器的糖以簡化理解):

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)

作品!

所以是Monad是適用的, Option[Future[T]]仍然是monad(在Future[T]但不在T本身上)但它允許你只使用Future[T]而不是T 為了將OptionFuture層“合並” - 您必須定義FutureT變換器FutureT ,以便將FutureOption合並 - 您必須定義OptionT 而且, OptionT在cats / scalaz中定義,但不是FutureT

一般來說(從這里 ):

不幸的是,我們真正的目標,monad的組成,更加困難。 ..事實上,我們實際上可以證明,在某種意義上,沒有辦法只使用兩個monad的操作來構造具有上述類型的連接函數(參見附錄中的證明大綱)。 因此,我們可能希望形成一個組合的唯一方法是,如果有一些額外的結構連接這兩個組件

正如我在OptionFuture展示的那樣,這個組合甚至不需要可交換(可交換)。

作為練習,您可以嘗試定義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),至少在“非阻塞”上下文中(像ScalaJs)。 這基本上意味着你不能“交換” FutureF ,就像Future[F[Future[B]] => F[Future[Future[B] 后者是一種自然變換(仿函數之間的態射),因此這解釋了對這個一般答案的第一個評論:

如果你能提供一個自然的轉換交換,你可以組成monads:NM a - > MN a

Applicative小號但是沒有這樣的問題-你可以很容易地編寫它們,但要記住的兩個組成導致Applicatives可能不是一個單子(但將永遠是一個適用)。 Nested[Future, Option, T]不是T上的monad,無論OptionFuture都是T上的monad。 使用簡單的單詞嵌套為類沒有flatMap

閱讀:

把它們放在一起( FG是單子)

  • F[G[T]]是在單子G[T] ,但不能在T
  • G_TRANSFORMER[F, T]才能從F[G[T]]得到T上的monad。
  • 沒有MEGA_TRANSFORMER[G, F, T]因為這樣的變換器不能構建在monad之上 - 它需要在G定義的額外操作(看起來G comonad就足夠了)
  • 每個monad(包括GF )都是適用的,但不是每個應用都是monad
  • 理論上, F[G[T]]G[T]T 然而,scala需要創建NESTED[F, G, T]以便在T上獲得組合應用(在cat庫中實現)。
  • NESTED[F, G, T]是適用的,但不是monad

這意味着你可以將Future x Option (又名Option[Future[T]] )組合成一個單一的monad(coz OptionT存在),但你不能在不知道的情況下OptionT Option x Future (又名Future[Option[T]] )除了作為monad之外,未來是另外的東西(即使它們本身就是應用的仿函數 - 應用程序還不足以構建monad或monad變換器)。 基本上:

  • OptionT可以看作是非交換二元運算符,定義為OptionT: Monad[Option] x Monad[F] -> OptionT[F, T]; for all Monad[F], T; for some F[T] OptionT: Monad[Option] x Monad[F] -> OptionT[F, T]; for all Monad[F], T; for some F[T] OptionT: Monad[Option] x Monad[F] -> OptionT[F, T]; for all Monad[F], T; for some F[T] 或者一般來說: Merge: Monad[G] x Monad[F] -> Monad[Merge]; for all T, Monad[F]; but only for **some of Monad[G]**, some F[T], G[T] Merge: Monad[G] x Monad[F] -> Monad[Merge]; for all T, Monad[F]; but only for **some of Monad[G]**, some F[T], G[T] Merge: Monad[G] x Monad[F] -> Monad[Merge]; for all T, Monad[F]; but only for **some of Monad[G]**, some F[T], G[T] ;

  • 你可以將任意兩個應用程序組成一個單獨的應用程序Nested: Applicative[F] x Applicative[G] -> Nested[F, G]; for all Applicative[F], Applicative[G], T; for some F[T], G[T] Nested: Applicative[F] x Applicative[G] -> Nested[F, G]; for all Applicative[F], Applicative[G], T; for some F[T], G[T] Nested: Applicative[F] x Applicative[G] -> Nested[F, G]; for all Applicative[F], Applicative[G], T; for some F[T], G[T]

  • 但你可以把任何兩個monad(固有的functor)組成一個applicative (但不是monad)。

托尼莫里斯發表了關於monad變壓器的演講,很好地解釋了這個問題。

http://tonymorris.github.io/blog/posts/monad-transformers/

他使用haskell,但這些例子很容易翻譯成scala。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM