trait Monoid[A] {
def op(a1: A, a2: A): A
def zero: A
}
def mapMergeMonoid[K, V](V: Monoid[V]): Monoid[Map[K, V]] = new Monoid[Map[K, V]] {
override def op(a1: Map[K, V], a2: Map[K, V]): Map[K, V] =
(a1.keySet ++ a2.keySet).foldLeft(zero) {
(acc, k) => acc.updated(k, V.op(a1.getOrElse(k, V.zero), a2.getOrElse(k, V.zero)))
}
override def zero: Map[K, V] = Map[K, V]()
}
As I understood, i can concat 2 Maps with this Monoid. But I cant understand, how to use it.
What i have to put into (V: Monoid[V])
argument to use op
method after and put there 2 Maps.
Say we want to combine two maps of type Map[Int, String]
val a1: Map[Int, String] = Map(1 -> "Picard")
val a2: Map[Int, String] = Map(1 -> "Worf", 2 -> "Data")
Then V
becomes String
which means we need to provide Monoid[String]
instance in order to specify how V
s will be combined
val stringMonoid: Monoid[String] = new Monoid[String] {
override def op(a1: String, a2: String) = a1 + a2
override def zero = ""
}
Putting it together we have
mapMergeMonoid(stringMonoid).op(a1, a2)
which outputs
res0: Map[Int,String] = Map(1 -> PicardWorf, 2 -> Data)
Conceptually, monoid provides a way of combining values, so when defining how to combine maps of type Map[K, V]
it makes sense we would need to also specify how the values V
of the map combine themselves. Hence Monoid[V]
is a necessary constituent element in the definition of Monoid[Map[K, V]]
:
Map[A, B]
is aMonoid
ifB
is aMonoid