Почему в скале нет экземпляра полугруппы для TrieMap

Хотя я могу сделать

Map("a" -> 1) |+| Map("a" -> 2)

Кажется, нет поддержки

TrieMap("a" -> 1) |+| TrieMap("a" -> 2)

Зачем?

1 ответ

Решение

Scalaz не предоставляет все возможные комбинации Type+Operation, которые образуют полугруппу, но вы можете легко реализовать ее, например, с помощью следующего implicit:

import scala.collection.concurrent.TrieMap
import scalaz._, Scalaz._

implicit def trieMapSemigroup[K: BuildKeyConstraint, V: Semigroup]: Semigroup[TrieMap[K, V]] =
  new Semigroup[TrieMap[K, V]] {
    def append(m1: TrieMap[K, V], m2: => TrieMap[K, V]) =
      (m1 /: m2) { case (res, (k, v)) =>
        res += (k -> res.get(k).cata(Semigroup[V].append(_, v), v))
      }
  }

Это дает вам, как и ожидалось:

scala> TrieMap("a" -> 1) |+| TrieMap("a" -> 2)
res: TrieMap(a -> 3)

Конечно, это будет работать для каждого значения как полугруппа, которая была определена в scalaz,


Что насчет моноида?

Если вы хотите оптимизированную версию implicit это работает как моноид тоже:

  implicit def trieMapMonoid[K: BuildKeyConstraint, V: Semigroup]: Monoid[TrieMap[K, V]] = new Monoid[TrieMap[K, V]] {
    def zero = TrieMap.empty[K, V]

    def append(m1: TrieMap[K, V], m2: => TrieMap[K, V]) = {
      val m2Instance: TrieMap[K, V] = m2
      val (from, to, semigroup) = {
        if (m1.size > m2Instance.size) (m2Instance, m1, Semigroup[V].append(_: V, _: V))
        else (m1, m2Instance, (Semigroup[V].append(_: V, _: V)).flip)
      }
      from.foldLeft(to) {
        case (res, (k, v)) => res += (k -> res.get(k).map(semigroup(_, v)).getOrElse(v))
      }
    }
  }

(код бесстыдный адаптирован из scalaz/std/Map.scala)

Другие вопросы по тегам