bitterharvest’s diary

A Bitter Harvestは小説の題名。作者は豪州のPeter Yeldham。苦闘の末に勝ちえた偏見からの解放は命との引換になったという悲しい物語

モナドを音楽の力を借りてアナログ的に説明する

4.8 モナドを関手(ファンクタ)を用いずに説明する

数学の本を読んでいると、1ページを読むのに数時間もかかることが往々にして起きる。特に、定理があってその証明が書かれているときがそうだ。純粋な数学的用語で書かれているときは、その背後にある概念を把握するまでにかなりの時間を取られ、読んでいるという感じではない。まるで、暗号を解読しているような状況に追い込まれてしまう。

最近は、日本の古代史や中世史の書籍を読む機会が多くなり、同じような経験をすることがある。研究論文に近い文章を読んでいるときは、それぞれの用語にある背景を吟味する必要があるため、一行の文章を理解するのに、長い時間を必要とする時がある。このような時は、前に何が書かれていたのかを忘れてしまい、同じページを行ったり来たりしながら読むことになる。

中世史の若手研究者の呉座勇一さんが書かれた書籍は、内容は高度だが、分かりやすい言葉で書かれていて、とても読みやすい。何冊か既に読んだが、『一揆の原理』の中に、面白い例があったので、紹介しよう。
f:id:bitterharvest:20161223112336j:plain
室町時代が始まった頃、朝廷は北朝南朝とに分かれていた。南北朝時代と呼ばれる。この時代が終わるころ、日本史研究者の間では「中世後期」と呼ばれる時代になると、一揆が社会全体に広がる。一揆にはいくつかのタイプがあり、その中に徳政一揆がある。簡単に言うと借金をチャラにしてくれというものだ。この時代になぜこのような一揆が生じるようになったかを解明するのが、歴史学者の役割である。

古い戦後歴史学では「悪徳高利貸に苦しめられた民衆の怒りが爆発し、徳政一揆をおこした」と考えられていたそうである。説明の内容は省くが、この記述の部分を論文調で書くと「貨幣経済の農村への浸透を契機とした都市高利貸資本の農村浸食」となるそうだ。相当に専門的な知識を有していないと理解するのに時間を要する。

圏論にも似たような点が多い。専門的な知識を有している仲間たちの間では、専門用語を多用して説明すれば、簡潔に述べることができるだろうが、あまり、知識を有しない人に同じように理解してもらうためには、平易な言葉で、比喩を多用しながら、逃げられないように説明する必要がある。

Milewskiが関手という専門用語を用いないでモナド(monad)の説明をしていた。これをヒントにして、同じように、関手を使わずに、モナドの説明を試みよう。数学とはだいぶ距離があるように思えるが、音楽の世界を利用する。小学校での音楽の時間に出会った曲に「朝はどこから」という歌があった。その中で、1番の歌詞の終わりの方に「おはよう」という部分がある。そこだけ楽譜に落とすと、次のようになる(原曲の楽譜とは異なっている)。
f:id:bitterharvest:20161225215157p:plain
少し単調なので、クラシック風にアレンジする。
f:id:bitterharvest:20161225222727p:plain

原曲からアレンジした曲へ矢印を引き、矢印に\(classic\)という名前を付けてみよう。
f:id:bitterharvest:20161226100237p:plain

なんとなく、圏に見えないだろうか。自分から自分への写像\(id\)をつけてみよう。図のように立派に圏になっていることが分かる。
f:id:bitterharvest:20161226100504p:plain

それでは、この楽譜を演奏したらどうなるだろう。
f:id:bitterharvest:20161226100718p:plain

上の図で、スピーカーのところを押したら曲が流れてくるとよいのだが、はてなブログでは、残念ながら、音楽をアップロードできない。仕方がないので、ブログDraw the Dotsを利用して聞いてほしい(その他にも、Music Editor - abcjs, abc Converter - MandolinTab.netなどがある)。

Draw the Dotsが開いたところで、長方形の枠の中に、ABC記法に従って楽譜を記入すると、下の方に五線譜での楽譜が表示される。また、midiファイルも用意されているので、これをダウンロードして視聴する。原曲の部分はABC記法では次のようになる。

X: 1
T: Original
Q: 1/4=100
M: 4/4
K: C
E2EFG4-|G6z2|
w: お は * よ ―

上記の楽譜を書き込んだブログDraw the Dotsの画面を下図に示す。
f:id:bitterharvest:20161226105506p:plain
画面右端の真ん中あたりにdownload midiがあるので、ここより、midiファイルを獲得し、視聴できる。
また、クラシック風にアレンジした曲は、ABC記法では以下のようになる。

X: 1
T: Classic
Q: 1/4=100
M: 4/4
K: G
B2 B1/2A1/2B1/2c1/2 dd1/2e1/2 d1/2c1/2B1/2c1/2|d6z2|
w: お は * * * よ * * ― * * * ―

聞き比べての印象はどうであろうか。うまくアレンジされているだろうか。midiで演奏された原曲とクラシック風の曲にも、楽譜の時と同じように、矢印を引くことができる(矢印に名前を付けるのはしばらく保留しておこう)。
f:id:bitterharvest:20161226110705p:plain

これもやはり恒等射を付加することで、立派な圏を得ることができる(二つの間の曲の射は実態が明らかになるまで?で示す)。
f:id:bitterharvest:20161226110839p:plain

さて、これまでに得た二つの圏を並べてみよう。
f:id:bitterharvest:20161226111255p:plain

ここで質問したい。楽譜で書かれた曲(赤い色の\(A\))とmidiで演奏された曲(緑色の\(A\))は、同じものだろうか。同じだという人もいるだろうし、違うという人もいるであろう。著作権をもとに考えれば同じだろう。物理的に考えると異なっているだろう。ある時は同じであるとみるし、別の時は異なるとみるのがモナドだ。そのため、惑わされてしまう。しかし、ここでは、この二つは同じものと考えておこう。

それでは、midiで演奏された二つの曲を結ぶ矢印は、楽譜で書かれた二つの曲の矢印と同じであろうか。後者の方の矢印は、ある規則に従っているのであれば、それはプログラムで表すことが可能である。このプログラムを用いて、一方のmidiの曲から他方のそれを作り出すことができるであろうか。これはどうも難しそうだ。

それでは、midi間での射を決めよう。そこで、次の図のように、楽譜の\(A\)から、midiの\(B\)を作り出す関数を考える。
f:id:bitterharvest:20161226113215p:plain
この関数は、先ほどのプログラムを実行した後にmidiに変換すればよいので、関数として定めることができる。この関数を\(classic?\)とする。midiでの二つの曲をつなぐ関数を今定義した関数\(classic?\)を用いることにする。
f:id:bitterharvest:20161226113802p:plain

この関数がモナドの神髄である。しかし、図を見る限り、midiの方の圏(対象が緑色で示されている)からは、赤色の\(A\)を発見することができない。なぜ、赤色の\(A\)を用いることができるのかと悩んでしまう。ここで、先ほどの赤色の\(A\)と緑色の\(A\)は同じというおまじないを使う。緑色の\(A\)があるのだから、緑色を剥げば、赤色の\(A\)が得られるだろうと考える。そこで、これを利用して、関数を適応する。Haskellでの型シグネチャを用いると次のように表すことができる。

classic? :: m a -> (a -> m b) -> m b

なお、上記の\(a\)は赤色の\(A\)であり、\(m \ a\), \(m \ b\)は緑色の\(A,B\)である(以下同じである)。

midiの曲の方を圏にするためには、自分から自分への射を必要とする。これも、少し、特殊である。楽譜からmidiで演奏するときの写像を考えよう。これを\(m\)と表すことにしよう。これを用いると次の図を得る。
f:id:bitterharvest:20161226115803p:plain

ここで得た関数\(m\)が、midiで演奏される曲の\(id\)となる。
f:id:bitterharvest:20161226124047p:plain

これは、楽譜(赤色の\(A\))とmidiによる演奏(緑色の\(B\))への写像\(classic?\)がmidiによる演奏間での射となったのと同じ理由である。Haskellの型シグネチャを用いると次のようになる。

idA :: m a -> (a -> m a) -> m a
idB :: m b -> (b -> m b) -> m b

圏論では射の合成も重要な役割をなす。そこで、クラシック風の曲をワルツ風の曲にアレンジしてみよう。
f:id:bitterharvest:20161226123246p:plain

ABC記法では以下のようになる。

X: 1
T: Classic
Q: 1/4=100
M: 4/4
K: G
B2 B1/2A1/2B1/2c1/2 dd1/2e1/2 d1/2c1/2B1/2c1/2|d6z2|
w: お は * * * よ * * ― * * * ―

アレンジした曲の関係は次の図のようになる。
f:id:bitterharvest:20161226124810p:plain

midiで演奏された曲の間では、原曲\(A\)からワルツ風の曲\(C\)への射\(compose?\)は、原曲\(A\)からワルツ風の曲\(B\)への射\(classic?\)とワルツ風の曲\(B\)からワルツ風の曲\(C\)への射\(waltz?\)との合成となる。即ち、\(compose?=waltz? \circ classic?\)となる。

Haskellの型シグネチャで表すと

classic? :: m a -> (a -> m b) -> m b
waltz? :: m b -> (b -> m c) -> m c
compose? :: m a -> ((a -> m b) -> m b -> (b -> m c)) -> m c

となる。\(compose?\)の関数\( ( (a \rightarrow m \ b) -> m \ b -> (b \rightarrow m \ c) )\)が二つの関数\( (a \rightarrow m \ b)\)と\( (b \rightarrow m \ c)\)との合成になっていることに注意してほしい。

ここまで、音楽を例にとって説明したが、説明した内容は汎用的である。このため、モナドを形成しているほかの世界にも応用することができる。例えば、カッコが使える世界を考えてみよう。
f:id:bitterharvest:20161226130355p:plain

カッコの世界では、\(A\)も\((A)\)同じである。これは、楽譜での曲\(A\)とmidiで演奏された曲\(A\)を同じと見做したのと同じ理屈である。\(f,f?\)のHaskellでの型シグネチャを求めると次のようになる。

f :: a -> b
f? :: m a -> (a -> m b) - m b

\((a)\)に\(f?\)を施すことを考えよう。\((a)\)は\(m \ A\)である。また、\(a\)は\(A\)である。そこで、\(aに(a \rightarrow m \ b)\)を施すと、\(m \ b\)を得る。従って、カッコの中の\(a\)が変わるので、\(f?\)を施すと\(( (b) )\)となる。外側のカッコはもともとあったもので、内側のカッコは今回の変換で得たものである。\((b)\)は\(b\)と同じなので、\(( (b) )\)は\((b)\)と同じである。即ち、カッコが付いたこの世界では、たくさんのカッコが付くことになるが、この世界ではあってもなくても同じである。

前に書いたクライスリ圏でも同じことが言えるが、これについては、確認して欲しい。