在scalaz中对未来单子的左身份法则的违反

在scalaz中对未来单子的左身份法则的违反,scala,monads,typeclass,Scala,Monads,Typeclass,假设我为Future定义了Monadtypeclass的一个实例: val futureMonad = new Monad[Future] { override def point[A](a: ⇒ A): Future[A] = Future(a) override def bind[A, B](fa: Future[A])(f: A => Future[B]): Future[B] = fa flatMap f } 严格来说,这不是单子,因为它违反了左身份法:

假设我为
Future
定义了
Monad
typeclass的一个实例:

val futureMonad = new Monad[Future] {
  override def point[A](a: ⇒ A): Future[A] =
    Future(a)

  override def bind[A, B](fa: Future[A])(f: A => Future[B]): Future[B] =
    fa flatMap f
}
严格来说,这不是单子,因为它违反了左身份法:

futureMonad.point(a) bind f == f(a)
如果
f
抛出异常,则左侧表达式的结果将是失败的
Future
,而右侧当然会抛出异常


但这种违反行为的实际含义是什么?由于这种“错误行为”,系统在哪些方面会失败?

单子,如
Try
Future
将一个单子定律换成另一个在其使用环境中更有用的定律: 由(
Try
Future
)、flatMap和map组成的表达式永远不会引发非致命异常。称之为“防弹”原则。
因此,实际上,这种方法确实可以保护您免受许多失败的影响,而左单位定律是故意失败的。

它只是意味着,就理解而言,以下重构并不是语义保留:

for (fut <- Future(a); x <- f(fut)) yield x  ==>  f(a)

for(fut如果“f”的类型为A=>Future[B],那么不应该直接导致应用程序出现失败的Future[B]…反之,如果f只是在bind方法中抛出一个异常,那么该异常是否仍然会从monad中“逃逸”…?任何函数都可以假设抛出一个异常(由于堆耗尽或其他原因)因此,基于你问题的前提……难道不是每个单子都违反了平等法吗?你是否混淆了行为平等的定义与类型/结构平等?即使f的类型A=>未来[B],它仍然可以抛出异常。而且,否:如果f在bind方法中抛出异常,它将不会逃逸。flatMap会处理这种情况。@不,因为大多数单子不尝试捕捉异常,所以它们会在等式的两边抛出异常,所以两边仍然“行为相等”.酷家伙们-我想看看下面的帖子,我想了解的是,如果一个单子通过在flatMap中捕获异常来遵守平等法,然后不允许它们逃逸(这不是纯粹的,因为异常是一种副作用),那么函数f也应该遵守同样的原则(防弹)否则谈论平等就有点毫无意义了。。。
for (fut <- Future(a); x <- f(fut)) yield x
==>  for (x <- f(a)) yield x  // by left identity law: WRONG, because left identity law does not hold
==>  f(a)                     // by 1st functor law:   WRONG, because previous line was wrong