加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

为什么monad不会在scala中构成

发布时间:2020-12-16 09:27:30 所属栏目:安全 来源:网络整理
导读:当Monad是一个应用者并且Applicative是一个Functor时,为什么monad不能编写.你在网上的许多文章中看到了这个继承链(我已经经历过).但是,当Functors和Applicatives组成为什么Monads打破了这个? 有人可以在scala中提供一个演示此问题的简单示例吗?我知道这被
当Monad是一个应用者并且Applicative是一个Functor时,为什么monad不能编写.你在网上的许多文章中看到了这个继承链(我已经经历过).但是,当Functors和Applicatives组成为什么Monads打破了这个?

有人可以在scala中提供一个演示此问题的简单示例吗?我知道这被问了很多,但没有一个简单的例子就很难理解.

解决方法

首先,让我们从一个简单的问题开始.比方说,我们需要得到一个包含在Future和Option中的两个整数的总和.让我们假设,我们使用猫库.

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

> Future和Option都应该在它们上面定义Monad实例
>我们还需要monadic变换器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的内部逻辑和结构(fold,None). EitherT,StateT等同样的问题

这里重要的是没有在猫中定义FutureT,所以你可以编写Future [Option [T]],但不能用Option [Future [T]]来做(后来我会证明这个问题是均匀的更通用的).

另一方面,如果您使用Applicative选择合成,您只需要满足一个要求:

> Future和Option都应该有针对它们定义的Applicative实例

你不需要任何特殊的变换器用于Option,基本上cat库提供适用于任何Applicative的嵌套类(让我们忘记应用构建器的糖以简化理解):

val fa = Nested[Future,Option,Int](Future(Some(1)))
val fb = Nested[Future,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,Int](Some(Future(1)))
fa.map(x => (y: Int) => y + x).ap(fb)

作品!

所以是Monad是适用的,选项[Future [T]]仍然是monad(在Future [T]上但不在T本身上)但是它允许你只用Future [T]而不是T操作.为了“合并”使用Future层的选项 – 您必须定义monadic变换器FutureT,以便将Future与Option合并 – 您必须定义OptionT.而且,OptionT在cats / scalaz中定义,但不是FutureT.

一般来说(从here):

Unfortunately,our real goal,composition of monads,is rather more
difficult. .. In fact,we can actually prove that,in a certain sense,
there is no way to construct a join function with the type above using
only the operations of the two monads (see the appendix for an outline
of the proof). It follows that the only way that we might hope to form
a composition is if there are some additional constructions linking
the two component

正如我在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 [未来[未来[B]这是自然变换的方式(仿函数之间的态射).这就解释了this general answer的第一条评论:

you can compose monads if you can provide a natural transformation swap : N M a -> M N a

然而,申请人没有这样的问题 – 你可以很容易地编写它们,但请记住,两个申请人的组成结果可能不是一个单子(但总是一个应用).嵌套[Future,T]不是T上的monad,不管Option和Future都是T上的monad.简单的单词Nested as a class没有flatMap.

阅读:

> http://typelevel.org/cats/tut/applicative.html
> http://typelevel.org/cats/tut/apply.html
> http://typelevel.org/cats/tut/monad.html
> http://typelevel.org/cats/tut/optiont.html

把它们放在一起(F和G是单子)

> F [G [T]]是G [T]上的单子,但不是T
>为了从F [G [T]]得到T上的monad,需要G_TRANSFORMER [F,T].
>没有MEGA_TRANSFORMER [G,F,T],因为这样的变换器不能构建在monad之上 – 它需要在G上定义的额外操作(看起来G上的comonad应该足够了)
>每个monad(包括G和F)都是适用的,但不是每个应用都是monad
>理论上F [G [T]]是G [T]和T的应用.但是scala需要创建NESTED [F,G,T]以便在T上得到组合应用(在cat库中实现) .
> NESTED [F,T]是适用的,但不是monad

这意味着您可以将Future x Option(又名[Option [T]])组合成一个monad,但是你不能在不知道它们是其他东西的情况下编写Option x Future(又名Future [Option [T]]).除了是单子.你可以将任意两个应用程序组合成一个单独的应用程序,你也可以将任意两个monad组成一个单一的应用程序(但不能组成一个单一的monad).

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读