我正在阅读以下书籍:
sealed trait Currency
case object USD extends Currency
... other currency types
case class Money(m: Map[Currency, BigDecimal]) {
... methods defined
}
讨论继续将
Money
上的某些类型的操作识别为Monoidal,因此我们想为Monoid
创建Money
。接下来是无法正确解析的列表。首先是
zeroMoney
的定义。这样做如下:final val zeroMoney: Money = Money(Monoid[Map[Currency, BigDecimal]].zero)
我在这里遇到的麻烦是
Money
参数列表中的部分。具体来说Monoid[Map[Currency, BigDecimal]].zero
这应该构造一些东西吗?到目前为止,在讨论中还没有实现
zero
的Monoid[Map[A,B]]
函数,这是什么意思?以下是以下内容:
implicit def MoneyAdditionMonoid = new Monoid[Money] {
val m = implicitly(Monoid[Map[Currency, BigDecimal]])
def zero = zeroMoney
def op(m1: Money, m2: Money) = Money(m.op(m1.m, m2.m))
}
在其他所有条件下,
op
的定义都很好,所以这不是问题。但是我仍然不明白给zeroMoney
定义了什么。这也给我隐式m
带来了同样的问题。那么,
Monoid[Map[Currency, BigDecimal]]
实际上是做什么的呢?我不知道它如何构造任何东西,因为Monoid
是没有实现的特征。如何在不先定义op
和zero
的情况下使用它? 最佳答案
为了编译该代码,您将需要以下内容:
trait Monoid[T] {
def zero: T
def op(x: T, y: T): T
}
object Monoid {
def apply[T](implicit i: Monoid[T]): Monoid[T] = i
}
因此,
Monoid[Map[Currency, BigDecimal]].zero
减少为Monoid.apply[Map[Currency, BigDecimal]].zero
,简化为implicitly[Monoid[Map[Currency, BigDecimal]]].zero
。Monoidal上下文中的
zero
是这样的元素:Monoid[T].op(Monoid[T].zero, x) ==
Monoid[T].op(x, Monoid[T].zero) ==
x
在
Map
的情况下,我假设Monoid
将Maps与++
结合在一起。然后,zero
将简单地是Map.empty
,这是Monoid[Map[Currency, BigDecimal]].zero
最终简化为的内容。编辑:comment的答案:
注意,这里根本不使用隐式转换。这是仅使用隐式参数的类型类模式。
这是一种实现方式,与我用
++
建议的方式不同。让我们来看一个例子。您如何将以下 map 组合在一起?Map(€ → List(1, 2, 3), $ → List(4, 5))
Map(€ → List(10, 15), $ → List(100))
您期望的结果可能是
Map(€ → List(1, 2, 3, 10, 15), $ → List(4, 5, 11))
,这仅是可能的,因为我们知道如何合并两个列表。我在这里隐式使用的Monoid[List[Int]]
是(Nil, :::)
。对于一般类型的B
,您还需要将两个B
粉碎在一起的东西,这称为Monoid
!为了完整起见,这是我猜这本书想要定义的
Monoid[Map[A, B]]
:implicit def mm[A, B](implicit mb: Monoid[B]): Monoid[Map[A, B]] =
new Monoid[Map[A, B]] {
def zero: Map[A, B] = Map.empty
def op(x: Map[A, B], y: Map[A, B]): Map[A, B] =
(x.toList ::: y.toList).groupBy(_._1).map {
case (k, v) => (k, v.map(_._2).reduce(mb.op))
}.toMap
}
关于Scala Monoid [Map [A,B]],我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42600662/