当前位置:  开发笔记 > 编程语言 > 正文

使用Scalaz自定义半群类时出现问题

如何解决《使用Scalaz自定义半群类时出现问题》经验,为你挑选了1个好方法。

scalaz.std.MapInstances声明任何值为a的地图Semigroup本身就是a Monoid.由于IntSemigroup,下面的代码工作:

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类的地图不被视为Monoids?



1> Travis Brown..:

Semigroup是一个类型类,这意味着在表示数据的类中扩展它不是预期的用法.

如果你熟悉Java,认为之间的差异ComparableComparator.如果您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同伴对象中放入一个隐式的type值,我们说这是我们想要在需要将Num实例添加到一起时使用的操作.

使用这种模式,而不是继承具有类似于的优点在于优势Comparator拥有Comparable在Java中:您可以将数据类型定义所有你可能需要对数据进行操作的定义分开,你可以有多个实例,等等. Scala通过允许您将类型类的实例放入隐式作用域中来进一步利用这些优势,这样您就不必手动传递它们(尽管您仍然可以在需要或想要时执行此操作).

推荐阅读
135369一生真爱_890
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有