簡體   English   中英

如何使用 Monoid Scala?

[英]How to use Monoid Scala?

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]()
  }

據我所知,我可以用這個 Monoid 連接 2 個 Map。 但我無法理解,如何使用它。 我必須放入(V: Monoid[V])參數以op之后使用op方法並放置 2 個 Maps。

Monoid是一個類型類 因此,建議學習我們如何在Scala 中對它們進行建模,它使用了implicits
具體來說Monoid[Map[K, V]]就是類型類推導,因為我們首先需要證明VMonoid ,為了證明Map[K, V]一個,對於所有Ks

這是定義此類typeclass及其實例及其操作/語法的規范方法。

trait Monoid[A] {
  def op(a1: A, a2: A): A

  def zero: A
}

object Monoid {
  implicit final val IntMonoid: Monoid[Int] = 
    new Monoid[Int] {
      override final def op(i1: Int, i2: Int): Int =
        i1 + i2

      override final val zero: Int = 0
    }

  implicit def mapMonoid[K, V](implicit vm: Monoid[V]): Monoid[Map[K, V]] =
    new Monoid[Map[K, V]] {
      override final def op(m1: Map[K, V], m2: Map[K, V]): Map[K, V] =
        (m1.keySet | m2.keySet).foldLeft(this.zero) {
          case (acc, key) =>
            acc + (key -> vm.op(
              m1.getOrElse(key, default = vm.zero),
              m2.getOrElse(key, default = vm.zero)
            ))
        }

      override final val zero: Map[K, V] = Map.empty
    }
}

object syntax {
  object monoid {
    implicit class MonoidOps[A] (private val a1: A) {
      def |+| (a2: A)(implicit M: Monoid[A]): A =
        M.op(a1, a2)
    }
  }
}

然后您可以像這樣使用它:

import syntax.monoid._ // Provides the |+| operator.

Map('a' -> 1, 'b' -> 2) |+| Map('b' -> 3, 'c' -> 5)
// res: scala.collection.immutable.Map[Char,Int] = Map(a -> 1, b -> 5, c -> 5)

最后,值得一提的是,雖然我相信第一次手動完成這些事情對於真正了解它們是如何工作的很好。 鼓勵使用提供這些抽象的穩定和生產就緒的庫,例如Cats

腳手架

假設我們想要組合兩個Map[Int, String]類型的Map[Int, String]

val a1: Map[Int, String] = Map(1 -> "Picard")
val a2: Map[Int, String] = Map(1 -> "Worf", 2 -> "Data")

然后V變成String這意味着我們需要提供Monoid[String]實例以指定V將如何組合

val stringMonoid: Monoid[String] = new Monoid[String] {
  override def op(a1: String, a2: String) = a1 + a2
  override def zero = ""
}

把它放在一起,我們有

mapMergeMonoid(stringMonoid).op(a1, a2)

哪個輸出

res0: Map[Int,String] = Map(1 -> PicardWorf, 2 -> Data)

從概念上講, monoid提供了一種組合值的方法,因此在定義如何組合Map[K, V]類型的Map[K, V]我們還需要指定映射的值V如何組合它們是有意義的。 因此Monoid[V]Monoid[Map[K, V]]定義中的必要組成元素:

Map[A, B]Monoid如果BMonoid

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM