Chapter 2: 二項演算とMonoid
Chapter 1で学んだcombineLatestWith
は、あらゆる2項演算をTimeline
の世界に持ち込むための、汎用的なプリミティブです。この章では、そのcombineLatestWith
をより具体的に、そして安全に利用するためのヘルパー関数群を定義します。
重要なのは、これから定義する2項演算が、Unit 2で学んだMonoidという数学的構造に基づいている点です。Monoidは、「ある型」「その型の2つの値を取り、同じ型の値を返す結合法則を満たす2項演算」「その演算における単位元」の3つの組で定義される代数的構造でした。
この章で示すのは、値レベルのMonoidが、combineLatestWith
(Applicativeのmap2
操作)によって、そのままTimeline
コンテナレベルのMonoidへと、その美しい構造を保ったまま引き継がれる様子です。
2項演算ヘルパー関数
Section titled “2項演算ヘルパー関数”これから紹介するorOf
, andOf
, addOf
, concatOf
といった関数は、すべてcombineLatestWith
を特定のMonoid演算で特殊化したものです。
論理和: orOf
Section titled “論理和: orOf”F#: orOF: Timeline<bool> -> Timeline<bool> -> Timeline<bool>
Section titled “F#: orOF: Timeline<bool> -> Timeline<bool> -> Timeline<bool>”TS: orOf(timelineA: Timeline<boolean>, timelineB: Timeline<boolean>): Timeline<boolean>
Section titled “TS: orOf(timelineA: Timeline<boolean>, timelineB: Timeline<boolean>): Timeline<boolean>”2つのTimeline<boolean>
を論理和(||
)で合成します。
この操作の基盤となるのは、boolean
型における論理和のMonoidです。
-
型:
boolean
-
2項演算:
||
(OR) -
単位元:
false
(false || x
は常にx
)
このMonoidの性質が、orOf
によってTimeline
レベルに引き継がれます。
// TS// 実装は combineLatestWith を利用しているconst orOf = (timelineA: Timeline<boolean>, timelineB: Timeline<boolean>): Timeline<boolean> => combineLatestWith((a: boolean, b: boolean) => a || b)(timelineA)(timelineB);
論理積: andOf
Section titled “論理積: andOf”F#: andOf: Timeline<bool> -> Timeline<bool> -> Timeline<bool>
Section titled “F#: andOf: Timeline<bool> -> Timeline<bool> -> Timeline<bool>”TS: andOf(timelineA: Timeline<boolean>, timelineB: Timeline<boolean>): Timeline<boolean>
Section titled “TS: andOf(timelineA: Timeline<boolean>, timelineB: Timeline<boolean>): Timeline<boolean>”2つのTimeline<boolean>
を論理積(&&
)で合成します。
これは、論理積のMonoidに基づいています。
-
型:
boolean
-
2項演算:
&&
(AND) -
単位元:
true
(true && x
は常にx
)
加算: addOf
Section titled “加算: addOf”F#: (F#版には直接のヘルパーなし。combineLatestWith (+)
を使用)
Section titled “F#: (F#版には直接のヘルパーなし。combineLatestWith (+) を使用)”TS: addOf(timelineA: Timeline<number>, timelineB: Timeline<number>): Timeline<number>
Section titled “TS: addOf(timelineA: Timeline<number>, timelineB: Timeline<number>): Timeline<number>”2つのTimeline<number>
を加算(+
)で合成します。
これは、数値の加算におけるMonoidに基づいています。
-
型:
number
-
2項演算:
+
(Addition) -
単位元:
0
(0 + x
は常にx
)
配列の結合: concatOf
Section titled “配列の結合: concatOf”F#: concatOf: Timeline<'a list> -> Timeline<'a> -> Timeline<'a list>
Section titled “F#: concatOf: Timeline<'a list> -> Timeline<'a> -> Timeline<'a list>”TS: concatOf(timelineA: Timeline<any[]>, timelineB: Timeline<any>): Timeline<any[]>
Section titled “TS: concatOf(timelineA: Timeline<any[]>, timelineB: Timeline<any>): Timeline<any[]>”concat
は、2つの配列を結合して1つの新しい配列を作る操作です。この単純な操作もまた、極めて重要なMonoidを形成します。
-
型:
array<'a>
(任意の型の配列) -
2項演算:
concat
(配列の結合) -
単位元:
[]
(空の配列) ([]
と任意の配列x
を結合しても、結果はx
のまま)
この「配列のMonoid」は、次章で登場するlistOf
を構築するための理論的な礎となります。
結論:Monoidの性質の継承
Section titled “結論:Monoidの性質の継承”ここまで見てきたように、combineLatestWith
は、値レベルで定義されたMonoid(加算、論理和、配列結合など)を、その性質を一切損なうことなく、Timeline
コンテナの世界へと持ち上げる役割を果たしています。
0
を足しても値が変わらないように、Timeline(0)
をaddOf
で加えてもTimeline
の振る舞いは変わりません。[]
と結合しても配列が変わらないように、Timeline([])
をconcatOf
で結合してもTimeline
の振る舞いは変わりません。
Applicative Functorのmap2
操作(ここではcombineLatestWith
)が、下層にあるMonoidの美しい代数的構造を、そのままコンテナレベルのMonoidへと継承させるのです。この堅牢な数学的基盤があるからこそ、我々は次章で、これらの部品を安心して組み上げ、より複雑な合成関数を構築することができます。