Scala with Cats学習メモ:Monoids and Semigroups

Scala with Cats を読んだので学習した内容のメモを残します。
2章のMonoids and Semigroupsです。

はじめに

Monoidは二項演算と単位元を持つ代数的構造であり、Catsでは型クラスが提供されている。

Monoidの定義

CatsでのMonoidの定義を簡略化したものが以下。

trait Monoid[A] {
  def combine(x: A, y: A): A
  def empty: A
}
  • combine(二項演算): A型の2つの値を結合させて1つのA型の値を返す
  • empty(単位元): A型の空要素を返す

という2つの操作がMonoidには定義されている。

combineとemptyの操作に加えて、Monoidはいくつかの法則に従う必要がある。

def associativeLaw[A](x: A, y: A, z: A)(implicit m: Monoid[A]): Boolean = {
  m.combine(x, m.combine(y, z)) == 
    m.combine(m.combine(x, y), z)
}
def identityLaw[A](x: A)(implicit m: Monoid[A]): Boolean = {
  (m.combine(x, m.empty) == x) && 
    (m.combine(m.empty, x) == x)
}

例えば整数の足し算、整数の掛け算、文字列の連結はこれらの法則に従うが、整数の引き算は従わない。

Semigroupの定義

SemigroupはMonoidのcombineの部分であり、emptyは含まない。

trait Semigroup[A] {
  def combine(x: A, y: A): A
}
trait Monoid[A] extends Semigroup[A] {
  def empty: A
}

CatsにおけるMonoid

Monoid型クラスは cats.kernel.Monoid で、cats.Monoid としてエイリアスされている。

catsパッケージから型クラスをimportする

import cats.Monoid
import cats.Semigroup

instance

import cats.Monoid
import cats.instances.string._ // for Monoid
Monoid[String].combine("Hi ", "there")
// res0: String = "Hi there"
Monoid[String].empty
// res1: String = ""

個々のinstanceをimportする理由がなければ全てをimportすればいい。

import cats._
import cats.implicits._

syntax
Catsは、|+| 演算子の形でcombineメソッドの構文を提供している。

Monoidの活用例

(1)ビッグデータ
SparkやHdoopのようなアプリケーションで複数マシンでの計算結果を組み合わせる

(2)分散システム
2つのデータをマージする際、この操作はMonoidであることに依存している

まとめ

Semigroupは加算や組み合わせの演算を表し、MonoidはSemigroupに恒等要素や ゼロ 要素を追加して拡張したもの