Scala Monoid[地图[A,B]]
Scala Monoid[Map[A,B]]
我正在阅读一本包含以下内容的书:
sealed trait Currency
case object USD extends Currency
... other currency types
case class Money(m: Map[Currency, BigDecimal]) {
... methods defined
}
讨论继续将 Money
上的某些类型的操作识别为 Monoidal,因此我们想为 Money
创建一个 Monoid
。接下来是我无法正确解析的列表。
首先是zeroMoney
的定义。这是按如下方式完成的:
final val zeroMoney: Money = Money(Monoid[Map[Currency, BigDecimal]].zero)
我在这里遇到的问题是 Money
参数列表中的部分。具体来说
Monoid[Map[Currency, BigDecimal]].zero
这是要构造什么东西吗?到目前为止,在讨论中还没有为 Monoid[Map[A,B]]
实现 zero
函数,那么这是什么意思?
接下来是:
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
。
zero
在 Monoidal 上下文中是满足
的元素
Monoid[T].op(Monoid[T].zero, x) ==
Monoid[T].op(x, Monoid[T].zero) ==
x
在 Map
的情况下,我假设 Monoid
结合了地图和 ++
。 zero
将简单地成为 Map.empty
,这就是 Monoid[Map[Currency, BigDecimal]].zero
最终简化为的内容。
编辑:对的回答:
注意隐式转换这里根本没有使用。这是仅使用隐式参数的类型 class 模式。
Map[A, B]
is a Monoid
if B
is a Monoid
这是一种方法,不同于我在 ++
中建议的方法。让我们看一个例子。您希望如何将以下地图组合在一起:?
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
}
我正在阅读一本包含以下内容的书:
sealed trait Currency
case object USD extends Currency
... other currency types
case class Money(m: Map[Currency, BigDecimal]) {
... methods defined
}
讨论继续将 Money
上的某些类型的操作识别为 Monoidal,因此我们想为 Money
创建一个 Monoid
。接下来是我无法正确解析的列表。
首先是zeroMoney
的定义。这是按如下方式完成的:
final val zeroMoney: Money = Money(Monoid[Map[Currency, BigDecimal]].zero)
我在这里遇到的问题是 Money
参数列表中的部分。具体来说
Monoid[Map[Currency, BigDecimal]].zero
这是要构造什么东西吗?到目前为止,在讨论中还没有为 Monoid[Map[A,B]]
实现 zero
函数,那么这是什么意思?
接下来是:
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
。
zero
在 Monoidal 上下文中是满足
Monoid[T].op(Monoid[T].zero, x) ==
Monoid[T].op(x, Monoid[T].zero) ==
x
在 Map
的情况下,我假设 Monoid
结合了地图和 ++
。 zero
将简单地成为 Map.empty
,这就是 Monoid[Map[Currency, BigDecimal]].zero
最终简化为的内容。
编辑:对
注意隐式转换这里根本没有使用。这是仅使用隐式参数的类型 class 模式。
Map[A, B]
is aMonoid
ifB
is aMonoid
这是一种方法,不同于我在 ++
中建议的方法。让我们看一个例子。您希望如何将以下地图组合在一起:?
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
}