为什么具有Monad实例的类型的Semigroupal不组合?
我正在尝试将我的头围绕在 Cats 中的 Semigroupals 上。以下是 Underscore 的“Scala with Cats”中的陈述。
cats.Semigroupal是一个允许我们组合上下文的类型类
trait Semigroupal[F[_]] {
def product[A, B](fa: F[A], fb: F[B]): F[(A, B)]
}
参数
fa和fb彼此独立:在将它们传递给 之前,我们可以按任一顺序计算它们product。这与 形成对比flatMap,后者对其参数施加了严格的顺序。
所以基本上,我们也应该能够结合两个Either上下文,但这似乎不起作用:
import cats.instances.either._
type ErrorOr[A] = Either[Vector[String], A]
Semigroupal[ErrorOr].product(Left(Vector("Error 1")), Left(Vector("Error 2")))
// res3: ErrorOr[Tuple2[Nothing, Nothing]] = Left(Vector("Error 1"))
如果 semigroupal 的 USP 急切地执行独立操作,则必须在传递给之前对两者进行评估product,但我们无法获得组合结果。
我们可能期望
product应用于Either累积错误而不是快速失败。同样,也许令人惊讶的是,我们发现它product实现了与 相同的 fail?fast 行为flatMap。
这是否与使用替代方法能够组合任何相同类型的上下文的原始前提相悖?
为了确保一致的语义,Cats 的 Monad(它扩展了 Semigroupal)根据
map和提供了产品的标准定义flatMap。
为什么product用mapand 来实现flatMap?这里指的是什么语义?
那么为什么要为半群而烦恼呢?答案是我们可以创建有用的数据类型,这些数据类型具有 Semigroupal(和 Applicative)的实例,但没有 Monad。这使我们能够以不同的方式实现产品。
这到底是什么意思?
不幸的是,本书没有详细介绍这些前提!网上也找不到资源。有人可以解释一下吗?TIA。
回答
所以基本上,我们也应该能够结合两个Either上下文,但这似乎不起作用:
它起作用了,正如您所看到的结果是一个有效的结果,它进行了类型检查。
Semigrupal只是暗示给定 anF[A]和 aF[B]它产生 anF[(A, B)]它并不意味着它能够独立地评估两者;可能会,但也可能不会。与Monad相反,它确实意味着它需要先求值F[A],因为要求值F[B]它需要A
这是否与使用替代方法能够组合任何相同类型的上下文的原始前提相悖?
并不是真正的不同方法,因为Monad[F] <: Semigroupal[F]你总是可以调用product任何Monad。在实施方面的功能Semigroupal只是意味着它是开放更多类型,但它不会改变各类型的行为。
为什么用map和flatMap来实现product?这里指的是什么语义?
TL; 博士; 一致性:
// https://github.com/typelevel/cats/blob/54b3c2a06ff4b31f3c5f84692b1a8a3fbe5ad310/laws/src/main/scala/cats/laws/FlatMapLaws.scala#L18
def flatMapConsistentApply[A, B](fa: F[A], fab: F[A => B]): IsEq[F[B]] =
fab.ap(fa) <-> fab.flatMap(f => fa.map(f))
上述定律意味着,对于任何F[A]和任何F[A => B]只要存在一个Monad (实际上是FlatMap),F那么,fab.ap(fa)就等于fab.flatMap(f => fa.map(f))
现在,为什么?多种原因:
- 最常见的一项最惊喜的原则,如果我有一堆eithers的,我将它们传递到一个通用的功能,无论是否需要单子或应用型我希望它快速失败,因为这是行为要么。
- Liskov,假设我有两个函数
fandg,f需要一个Applicative和g一个Monad,如果在后台g调用f,我希望调用它们返回相同的结果。 - 任何单子必须是应用型,但是一个积累应用型的版本要么需要一个半群的
Left,然而,在Monad的实例不需要。
这到底是什么意思?
这意味着我们可以定义另一种类型(例如Validated),它只满足Applicative定律而不满足Monad定律,因此它可以实现ap
额外的好处是,由于具有类型是Monad但可以实现不需要排序的Applicative 的情况非常普遍。该猫创建维护者并行来表示。
因此,与其将您的Thats转换为Validateds以使用它们来组合它们,mapN您可以parMapN直接在Yiis上使用。