30. Semigroup (半群)
• 群論の半群
• 定義(Wikipedia)
• 集合 S とその上の⼆項演算 • : S × S → S が与えられたとき、組 (S,
• ) が以下の条件を満たすならば、これを半群という。
• 結合律S の各元 a, b, c に対して、等式 (a • b) • c = a • (b • c) が満たされる。
• ⼆項演算(加法)
• 結合法則: (a + b) + c = a + (b + c)
• 例1: (1 + 2) + 3 = 1 + (2 + 3)
• 例2: (1 * 2) * 3 = 1 * (2 * 3)
• 例3: (“a” + “b”) + “c” = “a” + (“b” + “c”)
31. Monoid (モノイド)
• 半群に単位元の条件を追加したもの
• 定義(Wikipedia改)
• 集合 S とその上の⼆項演算 •: S × S → S が与えられ、以下の条件を
満たすならば、組 (S, •, e) をモノイドという。
• 結合律S の任意の元 a, b, c に対して、(a • b) • c = a • (b • c).
• 単位元の存在S の元 e が存在して、S の任意の元 a に対して e • a = a • e = a.
• 単位元: a + e = e + a = e (e: 単位元)
• 例1: 2 + 0 = 0 + 2 = 2
• 例2: 2 × 1 = 1 × 2 = 2
• 例2: “a” + “” = “” + “a” = “a”
32. Group (群)
• モノイドに逆元の条件を追加したもの
• 定義(Wikipedia)
• 集合 G とその上の⼆項演算 μ: G × G → G の組 (G, μ) が群であるとは、以下の3つの条件を満た
すことをいう:
• (結合法則)任意の G の元 g, h, k に対して、μ(g, μ(h, k)) = μ(μ(g, h), k) を満たす:
• (∀g, h, k ∈ G)[μ(g, μ(h, k)) = μ(μ(g, h), k)].
• (単位元の存在)μ(g, e) = μ(e, g) = g を G のどんな元 g に対しても満たすような G の元 e が存在する:
• (∃e ∈ G)(∀g ∈ G)[μ(g, e) = μ(e, g) = g].
• このような e は存在すれば⼀意であり、G の単位元という。
• (逆元の存在)G のどんな元 g に対しても、μ(g, x) = μ(x, g) = e となるような G の元 x が存在する:
• (∀g ∈ G)(∃x ∈ G)[μ(g, x) = μ(x, g) = e].
• このような x は存在すれば⼀意であり、この x を g の G における逆元といい、しばしば g−1, あるいは演算を加法的
に書く場合には −g で表される。
• 逆元: a + (-a) = (-a) + a = e (e: 単位元)
• 例1: 2 + (-2) = (-2) + 2 = 0
• 例2: 2 ×
!
"
=
!
"
* 2 = 1
• 例3: “a” + ??? = ??? + “a” = “”
33. Catsの定義
• Semigroup
• combine(x: A, y: A): A [⼆項演算]
• 法則 : SemigroupLawsで定義
• Monoid
• empty: A [単位元]
• 法則 : MonoidLawsで定義
• Group
• inverse(a: A): A [逆元]
• 法則 : GroupLawsで定義
43. case class Counter(c: Int) extends AnyVal:
def +(rhs: Counter): Counter = Counter(c + rhs.c)
object Counter:
val empty = Counter(0)
implicit object CounterEq extends Eq[Counter]:
def eqv(x: Counter, y: Counter) = x == y
implicit object CounterMonoid extends Monoid[Counter]:
def empty: Counter = Counter.empty
def combine(x: Counter, y: Counter): Counter = x + y
Counterの定義
CounterのMonoid型クラスの定義 emptyメソッド(単位元) を定義
Semigroup由来のcombineメソッド(結合法則を満たした⼆項演算)を定義
44. def legacyprocedual(ps: List[Int]): Counter =
var r = Counter.empty
for (i <- 0 until ps.length)
r = r + Counter(ps(i))
r
def procedual(ps: List[Int]): Counter =
var r = Counter.empty
for (x <- ps)
r = r + Counter(x)
r
⼿続き型での利⽤
伝統的⼿続き
モダン⽂法(Scala)での⼿続き
45. def functional(ps: List[Int]): Counter =
@annotation.tailrec
def go(ls: List[Int], c: Counter): Counter = ls match
case Nil => c
case x :: xs => go(xs, c + Counter(x))
go(ps, Counter.empty)
def morefunctional(ps: List[Int]): Counter =
ps.foldLeft(Counter.empty)((z, x) => z + Counter(x))
def algebraic(ps: List[Int]): Counter =
ps.foldMap(Counter.apply)
関数型での利⽤
関数型基本(再帰呼び出し)
代数的抽象(MonoidとFoldable)による実現
関数型畳み込み
46. class CounterPropertySpec extends AnyWordSpec with should.Matchers with
ScalaCheckDrivenPropertyChecks:
"Counter" should {
val nonNegativeInts = Gen.listOf(Gen.choose(0, 10000))
"Property-Based TestingでCounterのfoldMap動作をテストする" in
forAll(nonNegativeInts) { (xs: List[Int]) =>
val c: Counter = xs.foldMap(Counter.apply)
c.c should be(xs.sum)
}
}
Property-basedテスティングによるテスト
テストデータの特性を定義
Property−basedテスティングの実⾏
BDD (Behavior-Driven Development)スタイルのテスト
Travel Light
第16回 テスト
47. class CounterLawSpec extends AnyFunSuite with FunSuiteDiscipline with Configuration:
lazy val counterGen: Gen[Counter] = Gen.choose(0, 10000).map(Counter.apply)
implicit lazy val counterArbitrary: Arbitrary[Counter] = Arbitrary(counterGen)
checkAll("Counter", MonoidTests[Counter].monoid)
Monoid法則のテスト
Monoid法則のテストを⼀括して⾏う
型クラスの規則のテスト⽤トレイト