使用高级Scala功能实现半群的Scalaz
我正在研究Scalaz中s的实现。我遇到了一个操作符,如果你在幺半群上定义append操作,它应该是现成的。此运算符的定义采用SemigroupSyntax。那个类通过一个函数得到幺半群 在检查了这三个类之后,我有一个主要问题-SemigroupSyntax的注释是如何实现的使用高级Scala功能实现半群的Scalaz,scala,traits,implicits,monoids,semigroup,Scala,Traits,Implicits,Monoids,Semigroup,我正在研究Scalaz中s的实现。我遇到了一个操作符,如果你在幺半群上定义append操作,它应该是现成的。此运算符的定义采用SemigroupSyntax。那个类通过一个函数得到幺半群 在检查了这三个类之后,我有一个主要问题-SemigroupSyntax的注释是如何实现的/**包装了一个值'self',并提供了与'Semigroup`*/ 隐式调用,这是一种神奇的方法。这是关于trait的,还有半群语法中的更多内容,我真的不明白 如果有人能抽出时间来启发我,我会很高兴的 提前谢谢你 编辑:
/**包装了一个值'self',并提供了与'Semigroup`*/
隐式调用,这是一种神奇的方法。这是关于trait的,还有半群语法中的更多内容,我真的不明白
如果有人能抽出时间来启发我,我会很高兴的
提前谢谢你
编辑:
我渴望了解本课程的工作原理:
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)
////
}
及其在半群中的调用位置:
val semigroupSyntax = new scalaz.syntax.SemigroupSyntax[F] { def F = Semigroup.this }
这里最让人迷惑的是,实际上有两条途径可以对对象进行操作
默认的第一个路由是通过import scalaz.syntax.semigroup.\uz
。它为所有隐式可用的半组
实例添加运算符
任何半群
实例都为自己创建一个半群语法
的实现,用这个
定义它的F
方法
在scalaz/syntax/package.scala中,有一个syntax
singleton对象,它扩展了syntax
trait。这是导入定义的第一部分
在scalaz/syntax/syntax.scala中,在syntax
中使用的trait中有一个semigroup
单例对象,它扩展了到semigroupops
。我们正在导入此对象的内容,仅包含隐式转换。转换的目的是捕获隐式提供的Semigroup
实例,并构造一个包含所有操作的包装器SemigroupOps
第二条路线是一个快捷方式,import[your\u semigroup\u instance].semigroupSyntax.\u
,是semigroup
中的一个调用站点,您将被列出。它将运算符添加到一个特定的类型,对于该类型,半群
实例为
semigroupSyntax
是semigroupSyntax
特征的匿名实现,它的F
方法被定义为Semigroup
的特定实例
SemigroupSyntax
trait本身,与ToSemigroupOps
一样,提供了到SemigroupOps
的隐式转换,但它不捕获隐式提供的实例,而是使用其F
方法。因此,我们使用特定的半群
类型类实现,得到类型F
上的运算符
如果你粘贴了你不懂的代码,这将更容易帮助你。谢谢你的详细解释。尽管我读了好几遍,我还是不太明白,但我有一些简单的问题。在你看来,图书馆设计师如何从这些误导中获益?它是关于代码可扩展性的吗?因为在我看来,这个东西是很难维护的。设计实际上是相当模块化的:每个类型类一个文件,另一个用于语法,在syntax.scala中有一个线性注册(加上,scalaz.std
中的一些实例)。类型类及其语法包装器的代码遵循公共模式,虽然在Scalaz中没有使用,但它有一个通用的模式。虽然包装机制本身的设计非常类似于Haskell编码实践,看起来可能很复杂,但库体系结构仍然清晰且松散耦合。