scala - | + |是一个半群,为什么它需要一个monoid隐式解析

标签 scala functional-programming scalaz scalaz7

Semigroup的目的是确保关联性和封闭性
monoid的目标是基于Semigroup并提供其他标识。
当我使用| + |时半组追加器,为什么我要定义隐式monoid而不是隐式半组

这是我正在使用的代码reduceLeft,它不需要初始值

    val result1 = List(Staff("John", 36), Staff("Andrew", 30))
    val result2 = List(Staff("John", 40), Staff("Danny", 30))
    val result3 = List(Staff("Andrew", 30))
    val result4: List[Staff] = List()

    implicit val staffListSemigroup = new Monoid[List[Staff]] {

      override def zero: List[Staff] = Nil

      override def append(f1: List[Staff], f2: => List[Staff]): List[Staff] = {

        val mapSemigroup = f1.map(t => (t.name, t.numberOfTasks)).toMap |+| f2.map(t => (t.name, t.numberOfTasks)).toMap

        mapSemigroup.map(t => Staff(t._1, t._2)).toList

      }
    }

    val result = List(result1, result2, result3, result4).reduceLeft(_ |+| _)

    assert(result.size == 3)

如果staffListSemigroup为Semigroup [List [Staff]],则编译错误为值| + |。不是List [SemigroupSpec.this.Staff]的成员

另外,| + |的定义在Semigroup内
final class SemigroupOps[F] private[syntax](val self: F)(implicit val F: Semigroup[F]) extends Ops[F] {
  ////
  final def |+|(other: => F): F = F.append(self, other)
  final def mappend(other: => F): F = F.append(self, other)
  final def ⊹(other: => F): F = F.append(self, other)
  ////
}

提前谢谢了

编辑

@Travis回答,我认为这是不正确的。对于隐式值,特定值将始终覆盖通用值。这是我刚刚编写的代码示例:
case class Foo(i : Int, s : String)
class Test[T] {
  def print = "print test"
}

implicit val test = new Test[Any]
implicit val testMoreSpecific = new Test[Foo] {
  override def print = "print Foo"
}

def doStuff[A](implicit test: Test[A]) = {
  test.print
}

doStuff[Foo] //it successfully print out print Foo
doStuff //compilation error, ambiguous implicit value found

这是因为在Scalaz中,未指定在诸如Foo之类的方法中指定的类型。

最佳答案

问题是任何SemigroupList[A]已经有一个A。您已经为List[Staff]定义了一个更具体的实例,这导致了歧义,正如您通过询问实例可以看到的那样:

scala> Semigroup[List[Staff]]
<console>:17: error: ambiguous implicit values:
 both method listMonoid in trait ListInstances of type [A]=> scalaz.Monoid[List[A]]
 and value staffListSemigroup of type => scalaz.Semigroup[List[Staff]]
 match expected type scalaz.Semigroup[List[Staff]]
              Semigroup[List[Staff]]
                       ^

您可能会遇到麻烦,并尝试将Scalaz提供的实例置于范围之外,但请不要这样做!这对于其他用户而言可能非常令人困惑,并且违反了some basic good principles for working with type classes。相反,您可以为List[Staff]写一个包装器(一个简单的案例类就可以了),然后为该类型提供一个实例。

为了完整起见,值得注意的是,使用Monoid的版本可以编译,因为MonoidSemigroup更具体(有关此处适用的规则,请参见language specification的6.26.3节,但要警告它们有些困惑) 。

关于scala - | + |是一个半群,为什么它需要一个monoid隐式解析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25467936/

相关文章:

arrays - 为什么 Scalaz 中没有 Array 的 Functor 实例

Scala 解析器组合器 : Parsing in a stream

debugging - 在任意 scala 代码位置期间放入解释器

reference - 签名中的 SML 多态引用

haskell - 如何在 Haskell 中将其更改为 while 循环?

scala - 根据 bool 值在 Bifunctor 的 "side"上调用函数

scala - 如何将 Scalaz 7's EachT 与 LiftM 结合使用

Scala 2.10 反射 : Why do I get the same type "List()" for the list and list element?

scala - 如何找到两个数组列之间的共同元素?

scala - 中断或短路 Scala 中的折叠