Jay*_*Jay 16 monads scala higher-kinded-types
当Monad是一个应用者而一个Applicative是一个Functor时,为什么monad不能编写.你在网上的许多文章中看到了这个继承链(我已经经历过).但是,当Functors和Applicatives组成为什么Monads打破了这个?
有人可以在scala中提供一个演示此问题的简单示例吗?我知道这个问题很多,但没有一个简单的例子就很难理解.
dk1*_*k14 18
首先,让我们从一个简单的问题开始.比方说,我们需要得到两个整数的总和,每个包裹在两Future和Option.让我们使用cats库来使用Scala语法来模拟Haskell的标准库定义.
如果我们使用monad方法(aka flatMap),我们需要:
Future并Option应Monad在他们定义的实例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
Run Code Online (Sandbox Code Playgroud)
如果你看看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)))
Run Code Online (Sandbox Code Playgroud)
您会注意到代码非常特定于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)
Run Code Online (Sandbox Code Playgroud)
让我们交换选项和未来:
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)
Run Code Online (Sandbox Code Playgroud)
作品!
所以是Monad是Applicative,Option[Future[T]]仍然是一个monad(on Future[T]但不是它T自己)但它允许你只运行Future[T]not T.为了"合并" Option与Future图层-你必须定义单子变压器FutureT,以合并Future有Option-你必须定义OptionT.并且,OptionT在cat/scalaz中定义,但不是FutureT.
一般来说(从这里):
不幸的是,我们真正的目标,monad的组成,更加困难...事实上,我们实际上可以证明,在某种意义上,没有办法只使用两个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
})
Run Code Online (Sandbox Code Playgroud)
基本上这种实现的问题是你必须从r中"提取"值,这在这里是不可能的,假设你不能Future至少在"非阻塞"上下文中从(没有定义的comonad)中提取值(像ScalaJs).这基本上意味着你不能"交换" Future和F一样Future[F[Future[B]] => F[Future[Future[B].后者是一种自然的转换(仿函数之间的态射),所以这解释了对这个一般答案的第一个评论:
如果你能提供一个自然的转换交换,你可以组成monads:NM a - > MN a
Applicative然而,没有这样的问题 - 你可以很容易地组成它们,但要记住,两个人的组成结果Applicatives可能不是一个单子(但总是一个应用).Nested[Future, Option, T]是不是一个单子T,不管双方Option并Future都在单子T.插入简单的单词嵌套为类没有flatMap.
阅读:
把它们放在一起(F并且G是monad)
F[G[T]]是monad G[T],但不是TG_TRANSFORMER[F, T]为了得到一个单子上需要T从F[G[T]].MEGA_TRANSFORMER[G, F, T]因为这样的变换器不能构建在monad之上 - 它需要额外的操作定义G(似乎comonad on G应该就够了)G和F)都是适用的,但不是每个应用都是monadF[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存在),但是你不能在不知道Future是除了monad之外的其他东西的情况下编写Option x Future(aka Future[Option[T]])(尽管它们本身就是应用函数 - 应用程序不是足以既不建立monad也不构建monad变压器).基本上:
OptionT可以看作是非交换二元运算符定义为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];
你可以把任何两个应用程序组成一个单独的应用程序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).
| 归档时间: |
|
| 查看次数: |
1553 次 |
| 最近记录: |