0

我正在挖掘Scalaz中Monoid的实现。我遇到了|+| 如果您在 Monoid 上定义附加操作,则应该开箱即用的运算符。该运算符的定义在SemigroupSyntax中。该类通过Semigroup进入 Monoid 。

在检查了这三个类之后,我有一个主要问题 - SemigroupSyntax的评论究竟是如何实现的/** Wraps a value `self` and provides methods related to `Semigroup` */

在SemigroupSyntax中有一些隐含的魔法,调用.thistrait 等等,我真的不明白。

如果有人能花时间启发我,我会很高兴。

先感谢您!

编辑:

我很想了解这个类的工作原理:

package scalaz
package syntax

/** Wraps a value `self` and provides methods related to `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)
  ////
}

trait ToSemigroupOps  {
  implicit def ToSemigroupOps[F](v: F)(implicit F0: Semigroup[F]) =
    new SemigroupOps[F](v)

  ////
  ////
}

trait SemigroupSyntax[F]  {
  implicit def ToSemigroupOps(v: F): SemigroupOps[F] = new SemigroupOps[F](v)(SemigroupSyntax.this.F)

  def F: Semigroup[F]
  ////
  def mappend(f1: F, f2: => F)(implicit F: Semigroup[F]): F = F.append(f1, f2)

  ////
}

以及它在 Semigroup 中的呼叫站点:

val semigroupSyntax = new scalaz.syntax.SemigroupSyntax[F] { def F = Semigroup.this }
4

1 回答 1

0

这里最令人迷惑的是,实际上有两种方法可以对对象进行操作。

第一条路线,默认路线,是 by import scalaz.syntax.semigroup._。它为所有隐式可用Semigroup实例添加运算符。

  1. 任何实例都会为自己Semigroup创建一个实现,并根据.SemigroupSyntaxFthis
  2. 在 scalaz/syntax/package.scala 中,有一个扩展trait的syntax单例对象。Syntaxes它是导入定义的第一部分。
  3. 在 scalaz/syntax/Syntax.scala 中,在trait 中使用了一个semigroup单例对象,它扩展了. 我们正在导入这个对象的内容,只包含隐式转换。转换的目的是捕获隐式提供的实例并构造一个包含所有操作的包装器。SyntaxessyntaxToSemigroupOpsSemigroupSemigroupOps

第二条路线是一个快捷方式,您列出import [your_semigroup_instance].semigroupSyntax._了一个呼叫站点。Semigroup它将运算符添加到特定类型,Semigroup例如。

  1. semigroupSyntaxSemigroupSyntaxtrait 的匿名实现,该F方法被定义为Semigroup.
  2. SemigroupSyntaxtrait 本身,如ToSemigroupOps,提供到 的隐式转换SemigroupOps,但不是捕获隐式提供的实例,而是使用它的F方法。因此,我们F使用特定Semigroup的 typeclass 实现来获取 type 上的运算符。
于 2017-11-27T15:10:48.903 回答