何时使用来自scalaz的单子?

3
我想创建一个简单的计算包装器。内置的scala monads (TraversableLike) 对我来说似乎足够了。它们已经具备语法糖。从某种角度来看,scala集合traits是偶然的monads。而scalaz库提供了预期的monads。
什么样的用例可以受益于scalaz复杂类型类monads?哪些功能无法使用内置monads,并表明需要scalaz?
一些澄清。
这个问题不是继承vs类型类的圣战。我的问题是关于提供scalaz的基础设施。不是任何带有类型类方法的库,而是这个提到的库。它稍微复杂一些。但它也有一堆实用类,在scala集合库中没有对应物。因为它是一个集合库,而不是一个monadic库。所以问题是scalaz提供的额外功能。在哪些情况下这很重要?

编写纯I/O代码(scalaz.effect.IO, scalaz.concurrent.Task)如果没有monads,将会非常痛苦。 - ZhekaKozlov
所以问题是关于scalaz提供的额外功能。在哪些情况下它很重要?当人们调用您的类并想在使用scalaz类型类的通用代码中使用它们时,这就很重要了。 - Daenyth
1个回答

4
关于术语的问题:有时候使用诸如“Option是一个单子”这样的简写很有用,但是“Option有一个单子实例”或者“Option是单子的”更加清晰。说Scalaz提供了一堆单子可能会让人有点困惑——它提供了一个Monad类型类以及该类型类的实例给许多类型,包括它自己(例如\/Task等)和一些来自标准库的类型(例如ListOption等)。
因此,我将回答一个与您的问题类似的问题:相较于标准库提供的单子语法糖,使用明确的Monad类型类的价值在哪里?
其中一个使用明确Monad表示的好处在于当您想要定义自己的通用组合器或操作时非常有用。假设我想编写一个方法addM,它接受两个单子M[Int]值并在单子中将它们相加。对于Option很容易写出来:
def addM(oa: Option[Int], ob: Option[Int]): Option[Int] = for {
  a <- oa
  b <- ob
} yield a + b

或者用于列表:
def addM(oa: List[Int], ob: List[Int]): List[Int] = for {
  a <- oa
  b <- ob
} yield a + b

这两种实现显然有很多共同之处,如果我们能够编写一个通用的实现来同时处理这两种情况——以及任何其他单子类型,那将是很好的。如果我们只有标准库中模糊的单子语法,那么这将非常困难;如果我们拥有一个Monad类型类,那么这将非常容易。

TraversableLike 实际上是一个单子类。它具有所有单子方法。只是它的名称有误导性,并且拥有一堆冗余方法。 - ayvango
TraversableLike 不是一个类型类,它是一个基类,提供了一些类似单子的方法。 - Travis Brown
类型类不是 Scala 中可用于多态分派的唯一方法。我应该写一个关于如何使用 TraversableLike 来定义 addM 的泛型示例吗? - ayvango
这样的实现需要其泛型类型实现TraversableLike。这没问题,但在某些情况下,特定多态性更好。Scalaz旨在支持这些情况。 - Travis Brown
我同意。然而,我认为更大的原因是语义和在类型链中表达单子行为。 - raphaëλ
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接