9

Semigroup 的目标是确保关联性和闭合性 monoid 的目标是基于 Semigroup 并提供额外的 Identity。当我使用 |+| semigroup appender,为什么我定义隐式幺半群而不是隐式半群

这是我正在使用 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]],则编译错误为 value |+| 不是 List[SemigroupSpec.this.Staff] 的成员

另外,|+| 的定义 在半群内

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 这样的方法中指定的类型。

4

1 回答 1

8

问题是已经有一个Semigroupfor List[A]for any 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 提供的实例保持在范围之外,但请不要这样做!— 这可能会让其他用户非常困惑,并且违反了使用类型类的一些基本良好原则。相反,您可以为(一个简单的案例类)编写一个包装器List[Staff],然后为该类型提供一个实例。


为了完整起见,值得注意的是带有compilesMonoid因为的版本MonoidSemigroup(请参阅语言规范的第 6.26.3 节了解适用于此处的规则,但请注意它们有点混乱)。

于 2014-08-24T12:39:13.207 回答