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

时间:2014-08-24 02:06:06

标签: scala functional-programming scalaz scalaz7

Semigroup的目标是确保关联性和关闭性 monoid的目标是基于Semigroup并提供额外的身份。 当我使用| + | semigroup appender,为什么我定义了隐式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这样的方法中指定的类型。

1 个答案:

答案 0 :(得分:8)

问题在于Semigroup List[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]] ^ 定义了一个更具体的实例,这会导致模糊,正如您可以通过询问实例看到的那样:

List[Staff]

你可以跳过一些箍并尝试让Scalaz提供的实例超出范围,但请不要! - 对于其他用户而言可能非常混乱,并且违反了some basic good principles for working with type classes。相反,您可以为Monoid(一个简单的案例类)编写一个包装器,然后为该类型提供一个实例。


为了完整起见,值得注意的是,Monoid编译的版本因Semigroup更具体而不是{{1}}(参见language specification的第6.26.3节)适用于此处适用的规则,但要注意它们有点乱。)