gpt4 book ai didi

scala - 在 Scalaz 中使用自定义半群类时遇到问题

转载 作者:行者123 更新时间:2023-12-04 15:53:18 24 4
gpt4 key购买 nike

scalaz.std.MapInstances声明任何值为 Semigroup 的映射本身就是一个 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(_ |+| _)

谁能向我解释为什么 map 的值是我自定义的 Semigroup不考虑类 Monoid年代?

最佳答案

Semigrouptype class ,这意味着在表示您的数据的类中扩展它不是预期的用途。

如果您熟悉 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 通过允许您放置该类型的实例,进一步利用了这些优势类进入隐式范围,这样您就不必手动传递它们(尽管如果您需要或想要这样做,您仍然可以这样做)。

关于scala - 在 Scalaz 中使用自定义半群类时遇到问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34161436/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com