scalaz.std.MapInstances
声明任何值为a的映射Semigroup
本身就是a Monoid
。由于Int
是Semigroup
,下面的代码工作:
def merge[K](maps : Iterator[Map[K, Int]]) : Map[K, Int] = maps.reduce(_ |+| _)
但是,令我惊讶的是以下代码不起作用:
class Num(value : Int) extends Semigroup[Num] {
def append(x : Num, y : Num): Num = new Num(x.value + y.value)
}
def merge[K](maps : Iterator[Map[K, Num]]) : Map[K, Num] = maps.reduce(_ |+| _)
谁能向我解释为什么不将其值为我的自定义Semigroup
类的映射视为Monoid
s?
Semigroup
是一个类型类,这意味着在表示您的数据的类中扩展它不是预期的用法。
如果你熟悉Java,认为之间的差异Comparable
和Comparator
。如果Num
要用Java实现,并且希望支持比较Num
值,则可以使用您的Num
类实现Comparable[Num]
,也可以提供一个类型值Comparator[Num]
来描述如何比较两个Num
实例。
Semigroup
就像Comparator
,而不是Comparable
—您不需要扩展它,而是提供一个描述如何附加类型实例的值。请注意,在您的版本中,value
实例的参数未在实现中使用append
:
import scalaz.Semigroup
class Num(value: Int) extends Semigroup[Num] {
def append(x: Num, y: Num): Num = new Num(x.value + y.value)
}
相反,您将编写如下内容:
import scalaz.Semigroup
class Num(val value: Int)
object Num {
implicit val numSemigroup: Semigroup[Num] =
Semigroup.instance((a, b) => new Num(a.value + b.value))
}
接着:
scala> def merge[K](maps: List[Map[K, Num]]): Map[K, Num] = maps.reduce(_ |+| _)
merge: [K](maps: List[Map[K,Num]])Map[K,Num]
scala> val merged = merge(List(Map("a" -> new Num(1)), Map("a" -> new Num(2))))
merged: Map[String,Num] = Map(foo -> Num@51fea105)
scala> merged("a").value
res5: Int = 3
通过将类型的隐含价值Semigroup[Num]
在Num
的同伴对象,我们说,这是我们希望使用我们需要加在一起的任何时间的操作Num
实例。
使用这种模式,而不是继承具有类似于的优点在于优势Comparator
拥有Comparable
在Java中:您可以将数据类型定义所有你可能需要对数据进行操作的定义分开,你可以有多个实例,等等。 Scala允许您将类型类的实例放到隐式范围内,从而使这些优势更进一步,从而使您不必手动传递它们(尽管您仍然可以这样做)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句