Scala Monoid [地图[A,B]]

时间:2017-03-04 19:55:22

标签: scala functional-programming monoids

我正在读一本书,内容如下:

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的{​​{1}}函数,这是什么意思?

以下是:

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]]是一个没有实现的特征。如果不首先定义Monoidop,该如何使用?

1 个答案:

答案 0 :(得分:3)

要编译此代码,您需要以下内容:

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]].zeroMonoid.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,这是Map[A, B]最终简化为的内容。

编辑:回答comment

请注意,此处未使用隐式转换 。这是仅使用隐式参数的类型类模式。

  如果MonoidB

,则

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 } 我猜这本书想要定义:

x