02.05.2013 Views

圏 論 に よ る プログラミング と 論 理

圏 論 に よ る プログラミング と 論 理

圏 論 に よ る プログラミング と 論 理

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>圏</strong><strong>論</strong><strong>に</strong><strong>よ</strong><strong>る</strong><strong>プログラミング</strong><strong>と</strong><strong>論</strong><strong>理</strong><br />

shiatsumat (@shiatsumat)<br />

yingtai (@__int)<br />

172


序章 前書き<strong>に</strong>代えて<br />

こん<strong>に</strong>ちは. 皆さんは<strong>圏</strong><strong>論</strong> (category theory) <strong>と</strong>いう<strong>理</strong><strong>論</strong>をご存知で<br />

しょうか?<br />

「なんて読むんですか? けんろん?」<br />

「<strong>よ</strong>くわからないけど変わった数学らしい」<br />

「モナド<strong>と</strong>いう概念があって, Haskell はそれで⼊入出⼒力<strong>と</strong>かを実現してい<br />

て, 実はそれは<strong>圏</strong><strong>論</strong>の概念なんでしょ」<br />

……等々, いろいろな反応があ<strong>る</strong><strong>と</strong>思います.<br />

Haskell などの関数型<strong>プログラミング</strong>⾔言語のおかげで<strong>圏</strong><strong>論</strong>の知名度は⼀一<br />

般のプログラマーの間でも上がってきていますが, 「モナドがあって...」<br />

<strong>と</strong>いう以上の<strong>理</strong>解は⼀一般的<strong>に</strong>あまり得られていない⾯面があ<strong>る</strong><strong>と</strong>思います.<br />

また, <strong>プログラミング</strong><strong>に</strong>おけ<strong>る</strong><strong>圏</strong><strong>論</strong>の応⽤用<strong>に</strong>はさら<strong>に</strong>⾯面⽩白い側⾯面があ<strong>る</strong>の<br />

ですが, その部分はほ<strong>と</strong>んど注⽬目されていない<strong>よ</strong>う<strong>に</strong>思えます. その上,<br />

<strong>圏</strong><strong>論</strong><strong>に</strong>関す<strong>る</strong>プログラマーのための⽂文献は少なく, せっかく興味を持って<br />

も勉強しづらい<strong>と</strong>いうのが現状でしょう.<br />

この現状を憂えたわたしたちは, <strong>圏</strong><strong>論</strong><strong>に</strong>関す<strong>る</strong>総括的な⼊入⾨門記事を書く<br />

こ<strong>と</strong><strong>に</strong>しました. また同時<strong>に</strong>, <strong>論</strong><strong>理</strong>やラムダ計算, プログラムの再帰構造<br />

など<strong>に</strong>ついても解説しており, 全体<strong>と</strong>して関数型<strong>プログラミング</strong>の<strong>理</strong><strong>論</strong>的<br />

な基礎を⼀一から学べ<strong>る</strong><strong>よ</strong>う<strong>に</strong>なっています. この記事が皆さんの<strong>理</strong>解の⼀一<br />

助<strong>と</strong>なれば幸いです.<br />

記事の構成<br />

この記事は 3 部構成です. それぞれ「基礎<strong>理</strong><strong>論</strong>」, 「<strong>圏</strong><strong>論</strong><strong>と</strong>プログラミ<br />

ング」, 「<strong>圏</strong><strong>論</strong><strong>と</strong><strong>論</strong><strong>理</strong>学」<strong>と</strong>題しています.<br />

第Ⅰ部では, <strong>圏</strong><strong>論</strong><strong>に</strong>ついて学ぶ前<strong>に</strong>押さえておくべきこ<strong>と</strong>を解説します.<br />

まず初め<strong>に</strong>, 集合や写像, <strong>論</strong><strong>理</strong>などのごく基礎的な知識を第 1 章で扱い<br />

ます. 読んでいてわからない⽤用語などがあれば, 適宜ここを⾒見返す<strong>と</strong><strong>よ</strong>い<br />

でしょう.<br />

第 2 章ではラムダ計算<strong>に</strong>ついて扱います. 特<strong>に</strong>単純型付きラムダ計算<br />

(λ→) <strong>と</strong>その拡張を形式的<strong>に</strong>定義します.<br />

173


第 3 章では, <strong>プログラミング</strong><strong>に</strong>おけ<strong>る</strong>データ型を<strong>理</strong><strong>論</strong>的側⾯面から⾒見てい<br />

きます. 例えばデータ型の構成やプログラム再帰<strong>と</strong>いった概念はどの<strong>よ</strong>う<br />

<strong>に</strong>抽象的な仕⽅方で捉えられ<strong>る</strong>か<strong>と</strong>いったこ<strong>と</strong><strong>に</strong>ついて解説します. これら<br />

は後の<strong>圏</strong><strong>論</strong><strong>と</strong><strong>プログラミング</strong>の関係<strong>に</strong>直結す<strong>る</strong>内容<strong>と</strong>いえます.<br />

第Ⅱ部はこの記事の中⼼心<strong>と</strong>な<strong>る</strong>部分です. ここでは<strong>圏</strong><strong>論</strong><strong>と</strong>そのプログラ<br />

ミング<strong>に</strong>おけ<strong>る</strong>応⽤用<strong>に</strong>ついて, 第Ⅰ部の内容を参照しながら解説します.<br />

第 4 章では<strong>圏</strong><strong>論</strong>の基礎<strong>に</strong>ついて解説します. この章を読めば, 後の<strong>圏</strong><strong>論</strong><br />

<strong>に</strong>関す<strong>る</strong>章もスムーズ<strong>に</strong><strong>理</strong>解でき<strong>る</strong>でしょう.<br />

第 5 章では, CPL <strong>と</strong>いう⾔言語を通して, <strong>圏</strong><strong>論</strong><strong>と</strong>プログラムの関係を概観<br />

します.<br />

第 6 章では, <strong>圏</strong><strong>論</strong>から⾒見たプログラム<strong>に</strong>おけ<strong>る</strong>再帰構造<strong>に</strong>ついて解説し<br />

ます. 第 3 章で扱った計算<strong>理</strong><strong>論</strong>が<strong>圏</strong><strong>論</strong>を使う<strong>と</strong>綺麗<strong>に</strong>表せ<strong>る</strong>こ<strong>と</strong>が分か<strong>る</strong><br />

でしょう.<br />

第 7 章ではモナド<strong>と</strong>クライスリ<strong>圏</strong><strong>に</strong>ついて説明します.<br />

第Ⅲ部では, <strong>論</strong><strong>理</strong><strong>と</strong><strong>圏</strong><strong>論</strong><strong>と</strong>の関係<strong>に</strong>ついて解説します.<br />

第 8 章では, 第 1 章で簡単<strong>に</strong>扱った<strong>論</strong><strong>理</strong>の基礎<strong>に</strong>ついてきちん<strong>と</strong>解説<br />

します. ここでは<strong>圏</strong><strong>論</strong>の知識は前提<strong>と</strong>しません.<br />

第 9 章では<strong>論</strong><strong>理</strong><strong>と</strong>プログラムの関係<strong>に</strong>ついて扱います. まず 8 章で扱<br />

った「直観主義<strong>論</strong><strong>理</strong>」<strong>に</strong>ついて少し掘り下げていき, そこから<strong>論</strong><strong>理</strong><strong>と</strong>プロ<br />

グラムの対応関係を⾒見出した後, <strong>圏</strong><strong>論</strong>的な視点からその共通構造を⾒見てみ<br />

ます.<br />

各章の依存関係は下図の<strong>よ</strong>う<strong>に</strong>なっています.<br />

174


実線の⽮矢印は「A の章で説明したこ<strong>と</strong>を B の章で⽤用いてい<strong>る</strong>」こ<strong>と</strong>を表<br />

します. 破線の⽮矢印は「A の章を読む<strong>と</strong> B の章が<strong>よ</strong>りスムーズ<strong>に</strong><strong>理</strong>解でき<br />

<strong>る</strong>」こ<strong>と</strong>を表します.<br />

凡例<br />

初出語は「真 (truth, true)」の<strong>よ</strong>う<strong>に</strong>, 太字で表記した後英語での表<br />

記を添えます. また初出の⼈人名は「バートランド・ラッセル (Bertrand<br />

Arthur William Russell, 1872-1970)」の<strong>よ</strong>う<strong>に</strong>, ⽇日本語表記<strong>と</strong>アルファ<br />

ベット表記, ⽣生没年を記します.<br />

諸注意<strong>と</strong>お願い<br />

この記事は主<strong>に</strong>プログラマー, 特<strong>に</strong> Lisp 系⾔言語や ML 系⾔言語, Haskell,<br />

Erlang, F# のいずれか<strong>に</strong><strong>よ</strong><strong>る</strong>関数型<strong>プログラミング</strong><strong>に</strong>あ<strong>る</strong>程度慣れてい<br />

<strong>る</strong>⼈人を対象<strong>と</strong>しています. 特<strong>に</strong> 3, 5, 6 章はそれらの知識を前提します.<br />

数学の予備知識や<strong>圏</strong><strong>論</strong>の基礎, <strong>論</strong><strong>理</strong><strong>に</strong>関す<strong>る</strong>章は<strong>プログラミング</strong>をしない<br />

⼈人も読み物<strong>と</strong>して楽しめ<strong>る</strong><strong>よ</strong>う<strong>に</strong>なってい<strong>る</strong><strong>と</strong>思います.<br />

また, この記事はさまざまな話題を「広く浅く」扱うこ<strong>と</strong>を⽅方針<strong>と</strong>して<br />

書かれています. そのため, 必ずしも内容を深く掘り下げてい<strong>る</strong>わけでは<br />

ありません. 各トピック<strong>に</strong>ついての<strong>よ</strong>り深い<strong>理</strong>解のため<strong>に</strong>は, 記事の最後,<br />

参考⽂文献の章で案内されてい<strong>る</strong>資料が参考<strong>に</strong>な<strong>る</strong>か<strong>と</strong>思います.<br />

謝辞<br />

酒井政裕先⽣生は計算機科学<strong>と</strong><strong>圏</strong><strong>論</strong><strong>に</strong>ついて多くのこ<strong>と</strong>を教えてくださ<br />

いました. 本当<strong>に</strong>ありが<strong>と</strong>うございました.<br />

175


目次<br />

序章 前書き<strong>に</strong>代えて<br />

記事の構成<br />

凡例<br />

諸注意<strong>と</strong>お願い<br />

謝辞<br />

文字一覧<br />

第Ⅰ部<br />

基礎<strong>理</strong><strong>論</strong><br />

第 1 章 数学の予備知識<br />

集合<strong>論</strong>の基礎<br />

写像の基礎<br />

濃度<br />

<strong>論</strong><strong>理</strong>学の基礎<br />

関係<br />

公<strong>理</strong>的集合<strong>論</strong><br />

クラス<br />

宇宙<br />

第 2 章 ラムダ計算<br />

計算<strong>理</strong><strong>論</strong><strong>と</strong>は何か<br />

ラムダ計算<br />

単純型付きラムダ計算<br />

カリースタイル<strong>に</strong><strong>よ</strong><strong>る</strong>λ→の定義<br />

型の置換<br />

簡約<br />

カリースタイル/チャーチスタイル<br />

チャーチスタイル<strong>に</strong><strong>よ</strong><strong>る</strong>λ→の定義<br />

直和/直積<br />

ユニット型/ボトム型<br />

第 3 章 データ型の構成<br />

代数的データ型<br />

再帰的データ型<br />

最⼩小不動点<strong>と</strong>最⼤大不動点<br />

176<br />

第Ⅱ部<br />

<strong>圏</strong><strong>論</strong><strong>と</strong><strong>プログラミング</strong><br />

第 4 章 <strong>圏</strong><strong>論</strong>の基礎<br />

<strong>圏</strong>の定義<br />

意味を忘れ<strong>る</strong><br />

意味をあたえ<strong>る</strong><br />

コラム さまざまな<strong>圏</strong><br />

図式<br />

双対<br />

関⼿手<br />

⾃自然変換<br />

コラム <strong>圏</strong><strong>論</strong>の歴史<br />

ひ<strong>と</strong>しさ<br />

重なりあう<strong>圏</strong><br />

コラム さまざまな<strong>圏</strong> 2<br />

集合<strong>論</strong>をほどく<br />

随伴関⼿手<br />

コラム <strong>圏</strong><strong>論</strong><strong>と</strong>集合<strong>論</strong><br />

第 5 章 <strong>圏</strong><strong>論</strong><strong>プログラミング</strong>言語<br />

<strong>圏</strong><strong>論</strong><strong>プログラミング</strong>⾔言語<br />

開発環境の導⼊入<br />

データ型の定義<br />

双代数<br />

<strong>圏</strong><strong>論</strong>的データ型<br />

さまざまなデータ型<br />

プログラムの記述<br />

開発環境の使い⽅方<br />

関数<strong>と</strong>の格闘<br />

楽しい<strong>プログラミング</strong><br />

データ型の整<strong>理</strong><br />

<strong>よ</strong>り多くのデータ型<br />

どうして動くのか<br />

ま<strong>と</strong>め<br />

第 6 章 <strong>圏</strong><strong>論</strong><strong>と</strong>再帰<br />

代数<br />

代数の<strong>圏</strong>


余代数<br />

余代数の<strong>圏</strong><br />

CPL を思いだす<br />

カタモーフィズム<br />

アナモーフィズム<br />

有限<strong>と</strong>無限<br />

ハイロモーフィズム<br />

パラモーフィズム<br />

アポモーフィズム<br />

第 7 章 モナド<strong>と</strong>クライスリ<strong>圏</strong><br />

モナド<br />

Haskell のモナド<br />

クライスリ<strong>圏</strong><br />

モナド<strong>と</strong>クライスリ三つ組<br />

コラム <strong>圏</strong><strong>論</strong><strong>と</strong>哲学<br />

第Ⅲ部<br />

<strong>論</strong><strong>理</strong><strong>と</strong><strong>圏</strong><strong>論</strong><br />

第 8 章 <strong>論</strong><strong>理</strong>の基礎<br />

<strong>論</strong><strong>理</strong><strong>と</strong>は何か (再考)<br />

統語<strong>論</strong><strong>と</strong>意味<strong>論</strong><br />

⼀一階命題<strong>論</strong><strong>理</strong>の統辞<strong>論</strong><br />

⼀一階命題<strong>論</strong><strong>理</strong>のモデル<strong>論</strong>的意味<strong>論</strong><br />

⼀一階述語<strong>論</strong><strong>理</strong>の統辞<strong>論</strong><br />

⼀一階述語<strong>論</strong><strong>理</strong>のモデル<strong>論</strong>的意味<strong>論</strong><br />

証明<strong>論</strong><br />

コンビネータ<strong>論</strong><strong>理</strong> SK<br />

最⼩小<strong>論</strong><strong>理</strong> HM<br />

直観主義<strong>論</strong><strong>理</strong> HJ<br />

古典<strong>論</strong><strong>理</strong> HK<br />

演繹<strong>と</strong>証明<br />

⾃自然演繹<br />

シークエント計算<br />

第 9 章 <strong>論</strong><strong>理</strong><strong>と</strong>計算<strong>と</strong><strong>圏</strong><br />

直観主義<strong>論</strong><strong>理</strong><br />

ブラウワーの直観主義<br />

BHK 解釈<br />

177<br />

カリー=ハワード同型対応<br />

<strong>圏</strong><strong>論</strong><strong>と</strong>カリー=ハワード同型対応<br />

双デカルト閉<strong>圏</strong><br />

具体的な対応<br />

古典<strong>論</strong><strong>理</strong>への拡張<br />

さまざまな対応<br />

文献紹介<br />

記号一覧


文字一覧<br />

ギリシア文字 (Greek alphabet)<br />

⼤大⽂文字 ⼩小⽂文字 特殊な<br />

⼩小⽂文字<br />

⽇日本語読み ギリシア語<br />

読み<br />

英語表記<br />

Α α アルファ アルファ alpha<br />

Β β ベータ ヴィタ beta<br />

Γ γ ガンマ ガマ gamma<br />

Δ δ デルタ ゼルタ delta<br />

Ε ε ϵ エプシロン エ・プシロン epsilon<br />

Ζ ζ ゼータ ジタ zeta<br />

Η η イータ イタ eta<br />

Θ θ ϑ シータ シタ theta<br />

Ι ι イオタ ヨタ iota<br />

Κ κ カッパ カパ kappa<br />

Λ λ ラムダ ラムザ lambda<br />

Μ µμ ミュー ミ mu<br />

Ν ν ニュー ニ nu<br />

Ξ ξ グザイ クシ xi<br />

Ο ο オミクロン オ・ミクロン omicron<br />

Π π ϖ パイ ピ pi<br />

Ρ ρ ϱ ロー ロ rho<br />

Σ σ ς シグマ シグマ sigma<br />

Τ τ タウ タフ tau<br />

Υ υ ユプシロン イ・プシロン upsilon<br />

Φ φ ϕ ファイ フィ phi<br />

Χ χ カイ ヒ chi<br />

Ψ ψ プサイ プシ psi<br />

Ω ω オメガ オ・メガ omega<br />

黒板太字 (blackboard bold)<br />

178


文字一覧<br />

ギリシア文字 (Greek alphabet)<br />

⼤大⽂文字 ⼩小⽂文字 特殊な<br />

⼩小⽂文字<br />

⽇日本語読み ギリシア語<br />

読み<br />

英語表記<br />

Α α アルファ アルファ alpha<br />

Β β ベータ ヴィタ beta<br />

Γ γ ガンマ ガマ gamma<br />

Δ δ デルタ ゼルタ delta<br />

Ε ε ϵ エプシロン エ・プシロン epsilon<br />

Ζ ζ ゼータ ジタ zeta<br />

Η η イータ イタ eta<br />

Θ θ ϑ シータ シタ theta<br />

Ι ι イオタ ヨタ iota<br />

Κ κ カッパ カパ kappa<br />

Λ λ ラムダ ラムザ lambda<br />

Μ µμ ミュー ミ mu<br />

Ν ν ニュー ニ nu<br />

Ξ ξ グザイ クシ xi<br />

Ο ο オミクロン オ・ミクロン omicron<br />

Π π ϖ パイ ピ pi<br />

Ρ ρ ϱ ロー ロ rho<br />

Σ σ ς シグマ シグマ sigma<br />

Τ τ タウ タフ tau<br />

Υ υ ユプシロン イ・プシロン upsilon<br />

Φ φ ϕ ファイ フィ phi<br />

Χ χ カイ ヒ chi<br />

Ψ ψ プサイ プシ psi<br />

Ω ω オメガ オ・メガ omega<br />

黒板太字 (blackboard bold)<br />

178


第Ⅰ部<br />

基礎<strong>理</strong><strong>論</strong><br />

180


第1章 数学の予備知識<br />

この章では, <strong>圏</strong><strong>論</strong>の基礎を学ぶ前<strong>に</strong>知っておくべき数学の基礎的な⽤用語<br />

や記号などを紹介します. 直感的<strong>に</strong><strong>理</strong>解でき<strong>る</strong>内容なので, 難しい部分も<br />

少し粘ればわか<strong>る</strong><strong>と</strong>思います.<br />

<strong>と</strong>はいえ, この章は結構⻑⾧長いです. 勢いあまってこれからの話題<strong>に</strong>さほ<br />

ど関係がないこ<strong>と</strong>まで書いてい<strong>る</strong>ので, 分からないこ<strong>と</strong>があっても気<strong>に</strong>せ<br />

ず, 気楽<strong>に</strong>読んでください. 他の章で⾏行き詰まった<strong>と</strong>きも, この章<strong>に</strong>戻っ<br />

てきたらスムーズ<strong>に</strong><strong>理</strong>解でき<strong>る</strong>かもしれません.<br />

集合<strong>論</strong>の基礎<br />

集合<strong>論</strong> (set theory) は集合 (set) <strong>と</strong>いう同種のものの集まり<strong>に</strong>関す<br />

<strong>る</strong><strong>理</strong><strong>論</strong>です. 集合は場合<strong>に</strong><strong>よ</strong>っては系 (system), 族 (family) <strong>と</strong>もいい<br />

ます. 集合の集合は集合族 (family of sets) <strong>と</strong>呼ぶこ<strong>と</strong>が多いです.<br />

集合を構成す<strong>る</strong>それぞれの数学的対象を 元 または要素 (element,<br />

member) <strong>と</strong>いいます. x が集合 A の元であ<strong>る</strong>こ<strong>と</strong>を「x は A <strong>に</strong>属す<strong>る</strong> (x<br />

belongs to A)」もしくは「A は x を (元<strong>と</strong>して) 含む (A contains x (as an<br />

element) )」<strong>と</strong>いい,


第1章 数学の予備知識<br />

この章では, <strong>圏</strong><strong>論</strong>の基礎を学ぶ前<strong>に</strong>知っておくべき数学の基礎的な⽤用語<br />

や記号などを紹介します. 直感的<strong>に</strong><strong>理</strong>解でき<strong>る</strong>内容なので, 難しい部分も<br />

少し粘ればわか<strong>る</strong><strong>と</strong>思います.<br />

<strong>と</strong>はいえ, この章は結構⻑⾧長いです. 勢いあまってこれからの話題<strong>に</strong>さほ<br />

ど関係がないこ<strong>と</strong>まで書いてい<strong>る</strong>ので, 分からないこ<strong>と</strong>があっても気<strong>に</strong>せ<br />

ず, 気楽<strong>に</strong>読んでください. 他の章で⾏行き詰まった<strong>と</strong>きも, この章<strong>に</strong>戻っ<br />

てきたらスムーズ<strong>に</strong><strong>理</strong>解でき<strong>る</strong>かもしれません.<br />

集合<strong>論</strong>の基礎<br />

集合<strong>論</strong> (set theory) は集合 (set) <strong>と</strong>いう同種のものの集まり<strong>に</strong>関す<br />

<strong>る</strong><strong>理</strong><strong>論</strong>です. 集合は場合<strong>に</strong><strong>よ</strong>っては系 (system), 族 (family) <strong>と</strong>もいい<br />

ます. 集合の集合は集合族 (family of sets) <strong>と</strong>呼ぶこ<strong>と</strong>が多いです.<br />

集合を構成す<strong>る</strong>それぞれの数学的対象を 元 または要素 (element,<br />

member) <strong>と</strong>いいます. x が集合 A の元であ<strong>る</strong>こ<strong>と</strong>を「x は A <strong>に</strong>属す<strong>る</strong> (x<br />

belongs to A)」もしくは「A は x を (元<strong>と</strong>して) 含む (A contains x (as an<br />

element) )」<strong>と</strong>いい,


ここでタプル (tuple) <strong>と</strong>いう概念を導⼊入しておきます. タプル<strong>と</strong>は順<br />

序のついた列のこ<strong>と</strong>です. n 個の要素からな<strong>る</strong>タプルを n タプル, n 組<br />

(n-tuple) <strong>と</strong>いい,


ここでタプル (tuple) <strong>と</strong>いう概念を導⼊入しておきます. タプル<strong>と</strong>は順<br />

序のついた列のこ<strong>と</strong>です. n 個の要素からな<strong>る</strong>タプルを n タプル, n 組<br />

(n-tuple) <strong>と</strong>いい,


写像 f, g <strong>に</strong>ついて


これまで⾒見てきた写像は⼀一つの変数 x のみ<strong>に</strong><strong>よ</strong>って値が決定されまし<br />

た. しかし, 複数の変数<strong>に</strong><strong>よ</strong>って値が決定され<strong>る</strong>写像もあります. これを<br />

多変数写像 (multi-input mapping) <strong>と</strong>いいます. これは集合の直積を始<br />

域<strong>と</strong>す<strong>る</strong>写像だ<strong>と</strong>解釈できます. た<strong>と</strong>えば


な濃度です.<br />

<strong>論</strong><strong>理</strong>の基礎<br />

<strong>論</strong><strong>理</strong>学 (logic) は⼀一般的<strong>に</strong>⾔言って, 思考の法則, <strong>論</strong><strong>理</strong><strong>に</strong>関す<strong>る</strong>学問で<br />

す. 特<strong>に</strong>この記事では, いわゆ<strong>る</strong>数<strong>理</strong><strong>論</strong><strong>理</strong>学 (mathematical logic), つま<br />

り記号<strong>論</strong><strong>理</strong> (symbolic logic) を扱う<strong>論</strong><strong>理</strong>学<strong>に</strong>ついて触れたい<strong>と</strong>思います.<br />

記号<strong>論</strong><strong>理</strong><strong>と</strong>は⽂文字通り, 数学的な記号を使って<strong>論</strong><strong>理</strong>を表現す<strong>る</strong>ものです.<br />

記号<strong>論</strong><strong>理</strong>の体系<strong>に</strong>はいろいろなものがありますが, ここではいわゆ<strong>る</strong>古典<br />

<strong>論</strong><strong>理</strong> (classical logic), つまり中学/⾼高校で習う範囲の<strong>論</strong><strong>理</strong>を形式化した<br />

ものを紹介します.<br />

古典<strong>論</strong><strong>理</strong><strong>に</strong>は⼤大別して 2 種類あります. すなわち命題<strong>論</strong><strong>理</strong><strong>と</strong>, それを拡<br />

張した体系であ<strong>る</strong>⼀一階述語<strong>論</strong><strong>理</strong>です.<br />

命題<strong>論</strong><strong>理</strong> (propositional logic) は, 命題 (proposition) を「 か つ 」「 ま<br />

たは」「ならば」などの関係で結びつけた命題を調べ<strong>る</strong>ものです. 命題<strong>と</strong>は,<br />

真 (true, truth) または偽 (false, falsefood) であ<strong>る</strong>⽂文のこ<strong>と</strong>です.<br />

「1+1=2」「


分条件 (necessary and sufficient condition)」


「すべての」「あ<strong>る</strong>」<strong>と</strong>いう表現<strong>に</strong><strong>よ</strong>って, 命題の条件を満たすものの「量」<br />

を指定す<strong>る</strong>こ<strong>と</strong>を量化 (quantification) <strong>と</strong>いい, 量化のための記号を量<br />

化子 (quantifier) <strong>と</strong>いいます. ⼀一階述語<strong>論</strong><strong>理</strong>では, 以下の 2 種類の量化<br />

⼦子<strong>に</strong><strong>よ</strong>ってものを量化します.<br />

・ 全称量化子 (universal quantifier) は ∀ <strong>と</strong>書き表します.<br />


右全域的 (right-total) ∀


ックスがあります. 発⾒見者であ<strong>る</strong>バートランド・ラッセル (Bertrand<br />

Arthur William Russell, 1872-1970) が名前の由来です. これは次の<br />

<strong>よ</strong>うなパラドックスです:<br />

素朴集合<strong>論</strong><strong>に</strong>おいては, 「⾃自分⾃自⾝身を元<strong>と</strong>して含まない集合」<strong>と</strong>い<br />

う概念が考えられ<strong>る</strong>. ここで「⾃自分⾃自⾝身を元<strong>と</strong>して含まない集合」す<br />

べてからな<strong>る</strong>集合


冪集合の公<strong>理</strong> (axiom of power set)<br />

任意の集合 A <strong>に</strong>対して A の冪集合 (A の部分集合全体の集合) が存<br />

在す<strong>る</strong>.<br />

置換公<strong>理</strong> (axiom schema of replacement)<br />

関数クラスφ<strong>に</strong><strong>よ</strong><strong>る</strong>集合 A の像<strong>と</strong>な<strong>る</strong>集合 B が存在す<strong>る</strong>.<br />


(universe) <strong>と</strong>いいます.<br />

すべての集合の集まりは真のクラス<strong>と</strong>なってしまいます. そこで, すべ<br />

ての集合の集まりの<strong>よ</strong>うな振<strong>る</strong>舞いをしながらそれ⾃自⾝身も集合であ<strong>る</strong>グ<br />

ロタンディーク宇宙 (Grothendieck universe)<strong>と</strong>いうものを考えます. ア<br />

レクサンドル・グロタンディーク (Alexander Grothendieck, 1928-) が<br />

名前の由来です.<br />

数学的な定義を紹介しておきます. 集合


第 2 章 ラムダ計算<br />

計算機科学<strong>に</strong>おけ<strong>る</strong><strong>圏</strong><strong>論</strong>を学ぶ前<strong>に</strong>知っておくべきこ<strong>と</strong><strong>と</strong>して, ラムダ<br />

計算, 特<strong>に</strong>単純型付きラムダ計算<strong>に</strong>ついて説明します. 型付きラムダ計算<br />

は直接的<strong>に</strong>関数<strong>プログラミング</strong><strong>に</strong>関わ<strong>る</strong>モデルでもあります.<br />

この章では, まずラムダ計算<strong>に</strong>ついて概説した後, カリースタイルお<strong>よ</strong><br />

びチャーチスタイル<strong>に</strong><strong>よ</strong><strong>る</strong>ラムダ計算の形式的定義を紹介します. 第 8 章<br />

を先<strong>に</strong>読む<strong>と</strong>, この章の<strong>理</strong>解が<strong>よ</strong>りスムーズ<strong>に</strong>な<strong>る</strong>かもしれません.<br />

計算<strong>理</strong><strong>論</strong><strong>と</strong>は<br />

計算<strong>理</strong><strong>論</strong> (theory of computation) <strong>と</strong>は, 計算モデル (model of<br />

computation) やアルゴリズムを<strong>理</strong><strong>論</strong>的<strong>に</strong>扱う, 計算機科学の⼀一分野を指<br />

します. 計算 (computation) <strong>と</strong> は コンピュータで 扱え<strong>る</strong>情報処<strong>理</strong><br />

(information processing) のこ<strong>と</strong>です. 計算モデル<strong>と</strong>は⽂文字通り, コンピ<br />

ュータを抽象化したモデルのこ<strong>と</strong>をいいます.<br />

ラムダ計算<strong>と</strong>は<br />

ラムダ計算 (lambda calculus) は計算モデルの 1 つで, 関数の定義<strong>と</strong><br />

実⾏行を抽象化した体系です. 「1 つ」<strong>と</strong>⾔言っても実際<strong>に</strong>は⾊色々な種類があ<br />

り, 例えば型なしラムダ計算, 単純型付きラムダ計算, お<strong>よ</strong>びそのさまざ<br />

まな拡張 (λ-cube など) がこれ<strong>に</strong>含まれます. この記事ではこれらの拡<br />

張<strong>に</strong>ついて深く⽴立ち⼊入<strong>る</strong>こ<strong>と</strong>はせず, 単純型付きラムダ計算<strong>と</strong>その簡単な<br />

拡張だけを扱います.<br />

この分野では特<strong>に</strong>, 「写像」ではなく「関数」<strong>と</strong>いう語を使⽤用します.<br />

ラムダ計算では, 関数をラムダを使った記法で表記します. 例えば, 関<br />


<strong>と</strong>みなします.<br />

た<strong>と</strong>えば定義域<strong>と</strong>値域が⾃自然数であ<strong>る</strong> 2 変数関数


α-変換は束縛変数の名前は置換でき<strong>る</strong>こ<strong>と</strong>を意味し, β-簡約は関数の<br />

適⽤用を意味します. そして, η-変換は関数の外延性を意味します. それぞ<br />

れの変換<strong>に</strong><strong>よ</strong>って同値<strong>と</strong>な<strong>る</strong><strong>よ</strong>うな項の関係を, それぞれ α-同値, β-同<br />

値, η-同値 (*-equivalence) <strong>と</strong>呼びます.<br />

単純型付きラムダ計算 (simply typed lambda calculus) , あ<strong>る</strong>いは λ<br />

→ は, ラムダ計算<strong>に</strong>型 (type) <strong>と</strong>いう概念を導⼊入したものです. これは<br />

Int や Bool, String <strong>と</strong>いったプログラム<strong>に</strong>おけ<strong>る</strong>データ型<strong>に</strong>あた<strong>る</strong>もので<br />

す. <strong>論</strong><strong>理</strong><strong>に</strong>おけ<strong>る</strong>


α-変換は束縛変数の名前は置換でき<strong>る</strong>こ<strong>と</strong>を意味し, β-簡約は関数の<br />

適⽤用を意味します. そして, η-変換は関数の外延性を意味します. それぞ<br />

れの変換<strong>に</strong><strong>よ</strong>って同値<strong>と</strong>な<strong>る</strong><strong>よ</strong>うな項の関係を, それぞれ α-同値, β-同<br />

値, η-同値 (*-equivalence) <strong>と</strong>呼びます.<br />

単純型付きラムダ計算 (simply typed lambda calculus) , あ<strong>る</strong>いは λ<br />

→ は, ラムダ計算<strong>に</strong>型 (type) <strong>と</strong>いう概念を導⼊入したものです. これは<br />

Int や Bool, String <strong>と</strong>いったプログラム<strong>に</strong>おけ<strong>る</strong>データ型<strong>に</strong>あた<strong>る</strong>もので<br />

す. <strong>論</strong><strong>理</strong><strong>に</strong>おけ<strong>る</strong>


例えば任意の型


Γ ⊢


ルで既<strong>に</strong>対応す<strong>る</strong>定義がなされたものは省きます. 以後, λ→ やその拡張<br />

は基本的<strong>に</strong>チャーチスタイル<strong>に</strong><strong>よ</strong>って構成されたものを扱います.<br />

定義<br />

1. V を 変数の集合, Π を型の集合<strong>と</strong>します. この<strong>と</strong>き, 擬項<br />

(pseudo-terms) Λ !を以下の⽂文法で定義します.<br />

Λ ! ∷= V λx: Π. Λ ! (Λ ! Λ !)<br />

2. 型付け可能性の関係 ⊢ をカリースタイル<strong>と</strong>同様<strong>に</strong>定義します.<br />

3. λ→ は (Λ !, Π, ⊢) の三つ組です.<br />

厳密<strong>に</strong>は, ここで擬項<strong>と</strong>して定義したものは前擬項<br />

(pre-pseudo-terms) であり, ここから置換<strong>と</strong>α-同値<strong>と</strong>を定義した後<strong>に</strong><br />

擬項を定義す<strong>る</strong>必要がありますが, ここでは省略します.<br />

自由変数<br />

fv


表します. また関係 = ! (β-同値) は → ! の同値閉包です.<br />

λ→ <strong>に</strong>おいて, すべての項は有限回のβ-簡約<strong>に</strong><strong>よ</strong>って, 簡約の⼿手順<strong>に</strong><br />

関わらず正規形<strong>に</strong>なり, 停⽌止します. これを強正規化定<strong>理</strong> (strongly<br />

normalization theorem) <strong>と</strong>呼びます. これは λ→ が計算モデル<strong>と</strong>して<br />

チューリング不完全であ<strong>る</strong>こ<strong>と</strong>を意味します.<br />

直和/直積<br />

λ→ <strong>に</strong>直和<strong>と</strong>直積を導⼊入した体系を考えましょう.<br />

1. まず Λ ! を次の<strong>よ</strong>う<strong>に</strong>拡張します:<br />

Λ ! ∶≔ ⋯ Λ !, Λ ! π ! Λ ! | π ! Λ !<br />

| in ! !!! Λ! | in ! !!! Λ! | case(Λ !; V. Λ !; V. Λ !)<br />

2. 次<strong>に</strong>以下の 6 つの型付け規則を追加します.<br />

! ⊢ !: ! ! ⊢ !: !<br />

! ⊢ !,! ∶ !×!<br />

! ⊢ !: !<br />

! ⊢ !" !!!<br />

! ! ∶ !!!<br />

! ⊢ !: !×!<br />

! ⊢ ! ! ! : !<br />

! ⊢ !: !<br />

! ⊢ !" ! !!! ! ∶ !!!<br />

! ⊢ !: !!! !,!:! ⊢ !:! !,!:! ⊢ !:!<br />

! ⊢ !"#$ !;!.!;!.! :!<br />

3. 最後<strong>に</strong>簡約規則を追加します.<br />

a. π !


す.


第 3 章 データ型の構成<br />

前章では単純型付きラムダ計算<strong>に</strong>ついて概説しましたが, この章では型<br />

<strong>に</strong>ついてさら<strong>に</strong>掘り下げます.<br />

代数的データ型<br />

関数型<strong>プログラミング</strong>⾔言語では, 新たなデータ型の定義<strong>に</strong>代数的データ<br />

型 (algebraic data type) <strong>と</strong>呼ばれ<strong>る</strong>ものを⽤用います. ここでは Haskell<br />

の代数的データ型を例<strong>に</strong>取ります. 次の<strong>よ</strong>う<strong>に</strong>して (⽚片⽅方向の) リストを<br />

定義できます.<br />

data List a = Cons a (List a) | Nil<br />

代数的データ型<strong>に</strong>は型の引数を持たせ<strong>る</strong>こ<strong>と</strong>ができます. List は引数で<br />

あ<strong>る</strong>型 a を受け取って初めて型<strong>に</strong>な<strong>る</strong>ので, ⼀一種の関数の<strong>よ</strong>うなものだ<strong>と</strong><br />

考えられます. た<strong>と</strong>えば List Int は Int 型の要素を持つリストのこ<strong>と</strong>です.<br />

また, Cons や Nil <strong>と</strong>いうのはデータを構築す<strong>る</strong>ためのもので, データ構<br />

築子 (data constructor) <strong>と</strong>いいます. Cons の場合, 型 a の値<strong>と</strong>型 List a<br />

の値を元<strong>に</strong>して新た<strong>に</strong>型 List a のデータを作ります. Nil の場合, 何も受け<br />

取らず<strong>に</strong>データを作ります. Cons や Nil もやはり⼀一種の関数の<strong>よ</strong>うなもの<br />

だ<strong>と</strong>考えられます.<br />

代数的データ型を使う際, 多くの⾔言語<strong>に</strong>おいてパターンマッチ<br />

(pattern matching) が可能です. この機能<strong>に</strong><strong>よ</strong>って, データを「パターン」<br />

<strong>と</strong>して⾒見<strong>る</strong>こ<strong>と</strong>ができます. た<strong>と</strong>えば, リストの⼀一番初めの値を得たくて,<br />

なおかつリストが空だった<strong>と</strong>き<strong>に</strong>デフォルト値を得たい<strong>と</strong>いう<strong>よ</strong>うな場<br />

合, Haskell では<br />

headOrDefault :: a -> List a -> a<br />

headOrDefault d (Cons x xs) = x<br />

headOrDefault d Nil = d<br />

<strong>と</strong>書けばいいです.<br />

代数的データ型の特殊なもの<strong>と</strong>して, 直積<strong>と</strong>直和が考えられます.<br />

-- a×b<br />

data Prod a b = Pair a b<br />

fst' :: Prod a b -> a<br />

fst' (Pair x y) = x<br />

snd' :: Prod a b -> b<br />

203


snd' (Pair x y) = y<br />

-- a+b<br />

data Coprod a b = Inl a | Inr b<br />

case' :: (a->c) -> (b->c) -> Coprod a b -> c<br />

case' f g (Inl x) = f x<br />

case' f g (Inr y) = g y<br />

直積<strong>と</strong>直和は 2 章でラムダ計算<strong>に</strong>導⼊入したもの<strong>と</strong>同じで, 集合<strong>論</strong>的な直積<br />

<strong>と</strong>直和<strong>に</strong>それぞれ対応しています. Haskell <strong>に</strong>おいては, 直積<strong>と</strong>直和はそ<br />

れぞれタプル<strong>と</strong> Either 型<strong>に</strong>も対応しています. ⽇日常的<strong>に</strong>はこちらを使う<br />

こ<strong>と</strong>が多いでしょう.<br />

fst :: (a,b) -> a<br />

fst (x,y) = x<br />

snd :: (a,b) -> b<br />

snd (x,y) = y<br />

data Either a b = Left a | Right b<br />

either :: (a->c) -> (b->c) -> Either a b -> c<br />

either f g (Left x) = f x<br />

either f g (Right y) = g y<br />

いずれも標準で定義されています.<br />

代数的データ型は⼀一般<strong>に</strong>, 直積の直和であ<strong>る</strong><strong>と</strong>いえます. 例えば<br />

data List a = Cons a (List a) | Nil<br />

は実質的<strong>に</strong>は List


いので, 有限時間で計算を終え<strong>る</strong>プログラムを書くこ<strong>と</strong>ができます.<br />

⼀一般<strong>に</strong>, 再帰は不動点<strong>と</strong>して表されます. List a は<br />

data L a x = Cons a x | Nil<br />

<strong>と</strong>いうデータ型があ<strong>る</strong><strong>と</strong>き L a の不動点<strong>と</strong>なります. つまり L a x = x <strong>と</strong>な<br />

<strong>る</strong><strong>よ</strong>うな x が List a <strong>に</strong>あた<strong>る</strong>のです. 再帰を不動点<strong>と</strong>して扱うこ<strong>と</strong>は<strong>理</strong><strong>論</strong><br />

的な扱いの上でかなり重要です.<br />

実際, Haskell でもうまくデータ型を定義す<strong>る</strong>こ<strong>と</strong>で不動点を再現す<strong>る</strong><br />

こ<strong>と</strong>ができます.<br />

newtype Fix f = Fix (f (Fix f))<br />

data L a x = Cons a x | Nil<br />

type List a = Fix (L a)<br />

多少扱いが⾯面倒<strong>に</strong>なりますが, これでもちゃん<strong>と</strong>扱え<strong>る</strong>データを定義でき<br />

ます. た<strong>と</strong>えば先ほどの zeroForever は以下の<strong>よ</strong>う<strong>に</strong>なります.<br />

zeroForever :: List Int<br />

zeroForever = Fix (Cons 0 zeroForever)<br />

なお, 再帰的なデータ型のうち, 単純な⽅方法で不動点を使うこ<strong>と</strong>では表<br />

せない<strong>よ</strong>うなものもあります.<br />

data CrazyList a<br />

= CrazyCons a (CrazyList (a,a))<br />

| CrazyNil<br />

CrazyList a の定義の中でデータ構築⼦子の定義<strong>に</strong>おいて CrazyList (a,a)<strong>と</strong><br />

いう形で登場しており, Fix で定義す<strong>る</strong>のが難しくなっています. この<strong>よ</strong><br />

うなデータ型を非正則なデータ型 (non-regular data type) <strong>と</strong>いいます.<br />

これ以降は, この記事では⾮非正則なデータ型は扱いません.<br />

最小不動点<strong>と</strong>最大不動点<br />

再帰的な型を不動点で表しましたが, 実は不動点は⼀一つ<strong>と</strong>は限りません.<br />

不動点の中で, 型の⼤大きさ (集合<strong>と</strong>しての濃度) が⼀一番⼩小さいものを最⼩小<br />

不動点<strong>と</strong>いい, ⼀一番⼤大きいものを最⼤大不動点<strong>と</strong>いいます.<br />

集合<strong>論</strong>上普通<strong>に</strong>解釈すれば, 最⼤大不動点は無限のデータ構造を含む型で,<br />

最⼩小不動点は有限のデータ構造しか持たない型です.<br />

しかしながら, Haskell <strong>に</strong>おいては事情が特殊で, 有限のみのリストか<br />

らな<strong>る</strong>型は実際<strong>に</strong>は定義できません. なので, 最⼩小不動点も無限のデータ<br />

構造を含むもの<strong>と</strong>なり, 最⼩小不動点<strong>と</strong>最⼤大不動点は同じ<strong>に</strong>な<strong>る</strong>のです.<br />

205


第Ⅱ部<br />

<strong>圏</strong><strong>論</strong><strong>と</strong><strong>プログラミング</strong><br />

206


第 4 章 <strong>圏</strong><strong>論</strong>の基礎<br />

い<strong>よ</strong>い<strong>よ</strong><strong>圏</strong><strong>論</strong>の話をしていきます. ここまで⻑⾧長い道のりでしたね. しか<br />

し⾯面⽩白いのはここからです. 楽しみながら読み進めてください.<br />

さっそく, <strong>圏</strong>を定義していきます. そのあ<strong>と</strong>, そこから考えられ<strong>る</strong>⾊色々<br />

な概念<strong>に</strong>ついて説明します. 最初は<strong>よ</strong>くわからないかもしれませんが, 読<br />

み進め<strong>る</strong>うち<strong>に</strong>少しずつわかってく<strong>る</strong>はずです.<br />

<strong>圏</strong>の定義<br />

<strong>圏</strong> (category)


4. 対象 B <strong>に</strong>ついて, 恒等射 (identity morphism) id !:


ここまで読んで, 「<strong>圏</strong><strong>と</strong>は何か」「 対象<strong>と</strong>は何か」「 射<strong>と</strong>は何か」が<strong>よ</strong>く<br />

わからないな, <strong>と</strong>いう印象を受けたかもしれません. しかし, ここでは意<br />

味などどうでもいいのです. 意味をいったん忘れ<strong>る</strong>こ<strong>と</strong>が, <strong>圏</strong><strong>論</strong>を<strong>理</strong>解す<br />

<strong>る</strong>助け<strong>に</strong>なります. <strong>と</strong>いうのも, <strong>圏</strong><strong>論</strong>の⾯面⽩白さは, 具体的な「意味」のな<br />

い「抽象的な世界」を扱う<strong>と</strong>ころ<strong>に</strong>あ<strong>る</strong>のです.<br />

普段私たちが数学<strong>に</strong>ついて (あ<strong>る</strong>いはプログラム<strong>に</strong>ついて) 考え<strong>る</strong><strong>と</strong>き,<br />

どうしても集合<strong>と</strong>写像の⾔言葉<strong>に</strong>頼ってしまいます. しかし, これから学ん<br />

でいく<strong>圏</strong><strong>論</strong>的なものの⾒見⽅方を⾝身<strong>に</strong>着け<strong>る</strong><strong>と</strong>, それまで関係のなかった<strong>よ</strong>う<br />

<strong>に</strong>みえたいくつもの概念が⾃自然な形で結びついて⾒見えます. 「本質が⾒見え<br />

<strong>る</strong>」<strong>と</strong>⾔言っても過⾔言ではありません.<br />

数学は, 似てい<strong>る</strong>物事を抽象化し, ま<strong>と</strong>めて扱え<strong>る</strong><strong>よ</strong>う<strong>に</strong>す<strong>る</strong>学問であ<br />

<strong>る</strong><strong>と</strong>いえます. <strong>圏</strong><strong>論</strong>的なものの⾒見⽅方はこの意味で, ⾒見た⽬目以上<strong>に</strong>強⼒力なの<br />

です.<br />

意味をあたえ<strong>る</strong><br />

<strong>と</strong>はいえ, この記事で扱うのは計算機科学<strong>に</strong>おけ<strong>る</strong><strong>圏</strong><strong>論</strong>です. 抽象的<br />

なこ<strong>と</strong>はやはり難しいので, 具体的な<strong>圏</strong>を考えていきましょう.<br />

ここからは⼀一つの⼗十分⼤大きいグロタンディーク宇宙


コラム さまざまな<strong>圏</strong><br />

Set 以外のさまざまな<strong>圏</strong>をここで紹介しておきます.<br />

空<strong>圏</strong> (empty category) <strong>と</strong>は対象が存在しない<strong>圏</strong>のこ<strong>と</strong>です. 当<br />

然ながら射も存在しません. 離散<strong>圏</strong> (discrete category) <strong>と</strong>は各対象<br />

の恒等射以外<strong>に</strong>射が存在しない<strong>圏</strong>のこ<strong>と</strong>です.<br />

痩せた<strong>圏</strong> (thin category) <strong>と</strong>は任意の対象 A,B <strong>に</strong>ついて A から B<br />

への射が 0 本か 1 本しかない<strong>よ</strong>うな<strong>圏</strong>のこ<strong>と</strong>です. 射 f:A→B は単<strong>に</strong><br />

順序対 ⟨


図式<br />

さて, すで<strong>に</strong><strong>圏</strong><strong>論</strong>の定義で使った図式<strong>に</strong>ついて説明します.<br />

<strong>圏</strong> C 上の図式 (diagram) D は, C の対象を頂点で, 射を⽮矢印で表したも<br />

のです.<br />

図式<strong>に</strong>あ<strong>る</strong>射だけで合成射を作<strong>る</strong>こ<strong>と</strong>ができます. 図式<strong>に</strong>も<strong>と</strong>も<strong>と</strong>あ<strong>る</strong><br />

射<strong>と</strong>新しく作った合成射を合わせた射のあいだで, 始域<strong>と</strong>終域が同じ射ど<br />

うしは必ず等しい<strong>と</strong>き, その図式は可換 (commutative) であ<strong>る</strong><strong>と</strong>いいま<br />

す. 図式が可換であ<strong>る</strong>こ<strong>と</strong>は, 中<strong>に</strong>左回りの⽮矢印を書き⼊入れて表します.<br />

た<strong>と</strong>えば図式<br />

が可換であ<strong>る</strong><strong>と</strong>は ℎ ∘


双対は 2 つのものの表<strong>と</strong>裏, あ<strong>る</strong>いは左<strong>と</strong>右の<strong>よ</strong>うな関係です. <strong>圏</strong><strong>論</strong>で<br />

はさまざまな概念<strong>に</strong>明確な双対の関係を⾒見いだすこ<strong>と</strong>ができ, それが<strong>圏</strong><strong>論</strong><br />

の強みの⼀一つ<strong>と</strong>なっています.<br />

関手<br />

関手 (functor), もしくは共変関手 (covariant functor) <strong>と</strong>は, <strong>圏</strong>か<br />

ら<strong>圏</strong>への写像の<strong>よ</strong>うなものです. <strong>圏</strong> C から<strong>圏</strong> D への関⼿手 F を F:C→D <strong>と</strong><br />

書き表します. 関⼿手は対象<strong>に</strong>関す<strong>る</strong>写像<strong>と</strong>射<strong>に</strong>関す<strong>る</strong>写像からなります.<br />

この<strong>よ</strong>うな関⼿手 F <strong>に</strong>ついて,<br />

1. <strong>圏</strong> C の射


⼀一⽅方, 関⼿手 F,F’:C→D <strong>と</strong> G,G’:D→E があ<strong>る</strong><strong>と</strong>き, ⾃自然変換α:F→F’<strong>と</strong>β:G<br />

→G’<strong>に</strong>ついて, その2つの水平合成 (horizontal composite)


コラム <strong>圏</strong><strong>論</strong>の歴史<br />

<strong>圏</strong><strong>論</strong>が歴史的<strong>に</strong>どの<strong>よ</strong>うな発展を遂げてきたか<strong>に</strong>ついて少し話し<br />

たい<strong>と</strong>思います.<br />

<strong>圏</strong><strong>論</strong>が数学<strong>に</strong>初めて導⼊入されたのは 1940 年代のこ<strong>と</strong>で, サミュエ<br />

ル・アイレンベルグ (Samuel Eilenberg, 1913-1998) <strong>と</strong>ソーンダー<br />

ス・マックレーン (Saunders Mac Lane, 1909-2005) <strong>に</strong><strong>よ</strong>って, 代数<br />

的位相幾何学<strong>と</strong>いう分野での研究の⼀一部<strong>と</strong>して始まりました.<br />

その後, ホモロジー代数<strong>と</strong>いう分野<strong>に</strong>も役⽴立つこ<strong>と</strong>が知られ<strong>る</strong><strong>よ</strong>う<br />

<strong>に</strong>なりました. この分野<strong>に</strong>はアーベル<strong>圏</strong>や導来<strong>圏</strong>などの話題が出てき<br />

ます. また, 代数的幾何学<strong>と</strong>いう分野<strong>に</strong>も有⽤用であ<strong>る</strong>こ<strong>と</strong>がわかりま<br />

した. さら<strong>に</strong>は普遍代数の拡張<strong>に</strong>もつながり, ⾼高階<strong>論</strong><strong>理</strong>の表現など<strong>に</strong><br />

役⽴立っています.<br />

数学だけでなく, 数学の外の科学の分野でも<strong>圏</strong><strong>論</strong>は使われていま<br />

す. た<strong>と</strong>えば物<strong>理</strong>学<strong>に</strong>おいて, 数<strong>理</strong>物<strong>理</strong>学者のジョン・バエズ (John<br />

C. Baez, 1961-) が素粒⼦子のふ<strong>る</strong>まいを記述す<strong>る</strong>図であ<strong>る</strong>ファインマ<br />

ン・ダイアグラム<strong>と</strong>モノイダル閉<strong>圏</strong>の関係を⽰示しました. また, ブレ<br />

イドつきモノイダル<strong>圏</strong>も場の量⼦子<strong>論</strong>やひも<strong>理</strong><strong>論</strong>で応⽤用されています.<br />

計算機科学<strong>に</strong>おいても, 単純型付きラムダ計算<strong>と</strong>いう計算体系がデ<br />

カルト閉<strong>圏</strong><strong>と</strong>いう<strong>圏</strong><strong>に</strong><strong>よ</strong>って説明でき<strong>る</strong>こ<strong>と</strong>などがわかっており, 計<br />

算をモデル化す<strong>る</strong>の<strong>に</strong><strong>圏</strong><strong>論</strong>が⼤大い<strong>に</strong>役⽴立っています. クライスリ<strong>圏</strong>,<br />

いわゆ<strong>る</strong>モナドがプログラムの形式化<strong>に</strong>役だってい<strong>る</strong>, ……<strong>と</strong>いう話<br />

は, まさしくこの記事の主題です.<br />

また, <strong>圏</strong><strong>論</strong><strong>に</strong>おいてはモノイダル<strong>圏</strong>や三⾓角<strong>圏</strong>や⾼高次の<strong>圏</strong>などのバリ<br />

エーションも⽣生まれています. ⾼高次の<strong>圏</strong>は, 対象が 0 次元, 射が 1 次<br />

元<strong>と</strong>いえ<strong>る</strong>の<strong>に</strong>対し, <strong>よ</strong>り⾼高次元なものを扱うための道具です.<br />

実<strong>に</strong><strong>圏</strong><strong>論</strong>は, さまざまな応⽤用, 拡張がなされてきた分野なのです.<br />

214


1. <strong>圏</strong> C の射


自然変換 (natural transformation) <strong>と</strong>は, 関⼿手から関⼿手への写像の<br />

<strong>よ</strong>うなものです. ただし関⼿手どうしは, 始域が等しく終域も等しくなけれ<br />

ばなりません.<br />

関⼿手 F,G:C→D <strong>に</strong>ついて, F から G への⾃自然変換αを


ひ<strong>と</strong>しさ<br />

<strong>圏</strong><strong>論</strong>では, いろいろなレベルでの「ひ<strong>と</strong>しさ」を考えます. それぞれの<br />

ひ<strong>と</strong>しさを⽐比べてみましょう.<br />

まず, 相等 (equality). これは単純<strong>に</strong>イコール「=」の関係です. 相等<br />

は対象, 射, <strong>圏</strong>, 関⼿手, ⾃自然変換… あらゆ<strong>る</strong>もの<strong>に</strong>ついて考えられます.<br />

相等は⼀一番強い意味でのひ<strong>と</strong>しさです. しかし, もっ<strong>と</strong>弱い意味のひ<strong>と</strong>し<br />

さも⼤大事なのです.<br />

同型 (isomorphism) <strong>と</strong>は, ⾒見た⽬目は異な<strong>る</strong>けれども, 内部の構造はま<br />

ったく同じであ<strong>る</strong>こ<strong>と</strong>です.<br />

た<strong>と</strong>えば射 f:A→B <strong>に</strong>ついて


ら D への同値な関⼿手が存在す<strong>る</strong><strong>と</strong>き, <strong>圏</strong> C <strong>と</strong> D は同値 (equivalent) であ<br />

<strong>る</strong><strong>と</strong>いいます. <strong>圏</strong> C <strong>と</strong><strong>圏</strong> D の双対が同値であ<strong>る</strong><strong>と</strong>き, <strong>圏</strong> C <strong>と</strong> D は反変同値<br />

(contravariantly equivalent) もしくは双対的<strong>に</strong>同値 (dually<br />

equivalent) であ<strong>る</strong><strong>と</strong>いいます. なお, <strong>圏</strong> C <strong>と</strong>その双対が同値であ<strong>る</strong><strong>と</strong>き,<br />

<strong>圏</strong> C は自己双対 (self-dual) であ<strong>る</strong><strong>と</strong>いいます.<br />

A から B への準同型 (homomorphism) があ<strong>る</strong><strong>と</strong>は, A の構造が B の構<br />

造(の⼀一部)<strong>と</strong>して解釈でき<strong>る</strong>こ<strong>と</strong>です. A から B への準同型があっても B<br />

から A の準同型があ<strong>る</strong><strong>と</strong>は限りません. A から B への準同型<strong>と</strong> B から A へ<br />

の準同型があ<strong>る</strong>こ<strong>と</strong><strong>と</strong>, A <strong>と</strong> B は同型であ<strong>る</strong>こ<strong>と</strong>は, 同値です.<br />

重なりあう<strong>圏</strong><br />

<strong>圏</strong> C <strong>と</strong><strong>圏</strong> D があ<strong>る</strong><strong>と</strong>き,<br />

1. ob ℰ = ob


双関⼿手の重要な例のひ<strong>と</strong>つが hom 関手 (hom-functor) です. これは<br />

hom 集合の拡張<strong>に</strong>あた<strong>る</strong>ものです.<br />

局所的<strong>に</strong>⼩小さい<strong>圏</strong> C を考えます. 関⼿手


コラム さまざまな<strong>圏</strong>2<br />

<strong>圏</strong> C,D <strong>に</strong>おけ<strong>る</strong>関⼿手の<strong>圏</strong> Func(


コンマ<strong>圏</strong>は重要な<strong>圏</strong>です. なお, <strong>圏</strong> C の射の<strong>圏</strong>は (Id


要素は集合 A のいずれかの元<strong>に</strong>あたります.<br />

射 f:A→Bが任意の射 g,h:B→C <strong>に</strong>ついて


を満たす対象のこ<strong>と</strong>です. 直積は同型を除いて⼀一意<strong>に</strong>存在します.<br />

<strong>圏</strong> C <strong>に</strong>おけ<strong>る</strong>直積「×」は双関⼿手


を満たす対象のこ<strong>と</strong>です. 直和は同型を除いて⼀一意<strong>に</strong>存在します. 直和は<br />

直積の双対です.<br />

<strong>圏</strong> C 上の直和「+」も双関⼿手


を満たす対象のこ<strong>と</strong>です. 冪対象は同型を除いて⼀一意<strong>に</strong>存在します. なお,<br />

eval は値付け (evaluation arrow) , ℎ は h の転置 (transpose) <strong>と</strong>いい<br />

ます.<br />

Set <strong>に</strong>おいて, 冪対象 (exponential object)


が存在す<strong>る</strong><strong>と</strong>き,


コラム <strong>圏</strong><strong>論</strong><strong>と</strong>集合<strong>論</strong><br />

ここまで読んで, 「<strong>圏</strong><strong>論</strong>も結局は集合<strong>論</strong>の⾔言葉で書かれて<strong>る</strong>じゃん」<br />

<strong>と</strong>思った⼈人もい<strong>る</strong>かもしれません. 集合<strong>論</strong>を使って考え<strong>る</strong>のが分かり<br />

やすいので, ここでは<strong>圏</strong><strong>論</strong>の説明<strong>に</strong>⽤用いましたが, 実際は<strong>圏</strong>の世界を<br />

集合<strong>論</strong><strong>と</strong>関係のない公<strong>理</strong>を使って描くこ<strong>と</strong>は可能です. 「射の集合」<br />

「対象の集合」などの概念を使わず<strong>に</strong>議<strong>論</strong>すればいいのです. もちろ<br />

ん技術的な難しさはいろいろありますが, なん<strong>と</strong>かなります.<br />

さら<strong>に</strong>, <strong>圏</strong><strong>論</strong><strong>に</strong>基づいて集合<strong>論</strong>を体系化し<strong>よ</strong>う<strong>と</strong>いう動きもありま<br />

す. あ<strong>る</strong>⽅方法では, 初等トポス (elementary topos) <strong>と</strong>いう<strong>圏</strong>を使い<br />

ます. 初等トポス<strong>と</strong>は,「終対象・引き戻し (pullback)・真<strong>理</strong>値の対象・<br />

『真』の射・冪対象 (この章で紹介したもの<strong>と</strong>は違い, 冪集合<strong>に</strong>近い) 」<br />

を持つものです. 詳しい説明は省略します. この初等トポス<strong>に</strong><br />

「well-‐‑‒pointed であ<strong>る</strong>・選択公<strong>理</strong>を持つ・⾃自然数対象を持つ」<strong>と</strong>いう<br />

性質を付加したものを集合の<strong>圏</strong><strong>と</strong>す<strong>る</strong>, つまり対象を集合<strong>と</strong>し, 射を<br />

写像<strong>と</strong>す<strong>る</strong>, <strong>と</strong>いうこ<strong>と</strong>です. こうして定義された集合は, ZF 公<strong>理</strong>系<br />

で定義され<strong>る</strong>集合の⼀一部<strong>と</strong>なります. 残念ながら, すべてではないの<br />

です. それでも, これから<strong>圏</strong><strong>論</strong>が数学の有⼒力な基礎<strong>論</strong><strong>と</strong>して使われ<strong>る</strong><br />

可能性は⼗十分<strong>に</strong>あ<strong>る</strong><strong>と</strong>思います.<br />

227


第 5 章 <strong>圏</strong><strong>論</strong><strong>プログラミング</strong>言語<br />

ではい<strong>よ</strong>い<strong>よ</strong>, <strong>圏</strong><strong>論</strong>を使って<strong>プログラミング</strong>をしていきましょう. この<br />

章では, <strong>圏</strong><strong>論</strong><strong>プログラミング</strong>⾔言語を学び, この⾔言語を通して, <strong>圏</strong><strong>論</strong>を使っ<br />

てどの<strong>よ</strong>う<strong>に</strong><strong>プログラミング</strong>ができ<strong>る</strong>かを⾒見ていきます.<br />

<strong>圏</strong><strong>論</strong><strong>プログラミング</strong>言語<br />

<strong>圏</strong><strong>論</strong><strong>プログラミング</strong>言語 (Categorical Programming Language, CPL)<br />

は, 1987 年<strong>に</strong>萩野達也教授が発案した<strong>プログラミング</strong>⾔言語です. CPL では,<br />

プログラムを純粋<strong>に</strong><strong>圏</strong><strong>論</strong>の概念だけで記述します. 単純な⽂文法でありなが<br />

ら, ⾮非常<strong>に</strong>幅広い概念を記述できます.<br />

開発環境の導入<br />

CPL の実⾏行環境<strong>と</strong>して, 酒井政裕⽒氏<strong>に</strong><strong>よ</strong>って Haskell で実装されたイン<br />

タプリタがあります. これは Hackage から簡単<strong>に</strong>インストールできます.<br />

http://hackage.haskell.org/package/CPL<br />

まず, Haskell のコンパイラをインストールしておきましょう. Haskell<br />

Platform を導⼊入す<strong>る</strong>こ<strong>と</strong>をお勧めします.<br />

http://www.haskell.org/platform/<br />

Hackage のライブラリをインストールす<strong>る</strong><strong>に</strong>は, ⼿手動です<strong>る</strong>⽅方法もあり<br />

ますが, cabal <strong>と</strong>いうパッケージ管<strong>理</strong>システムを使うほうが便利です.<br />

cabal は Haskell Platform <strong>に</strong>標準装備されています.<br />

$ cabal install cpl<br />

した後, cpl コマンドでインタプリタを起動でき<strong>る</strong><strong>よ</strong>う<strong>に</strong>なります.<br />

(Windows の場合は C:¥Users¥***¥AppData¥Roaming¥cabal¥bin <strong>に</strong><br />

実⾏行ファイルが⼊入っています.)<br />

データ型の定義<br />

ではい<strong>よ</strong>い<strong>よ</strong>, CPL の⽂文法<strong>に</strong>ついて⾒見ていきましょう.<br />

CPL で定義す<strong>る</strong>データ型<strong>に</strong>は「左データ型」<strong>と</strong>「右データ型」があり, そ<br />

れぞれ以下の<strong>よ</strong>う<strong>に</strong>定義します.<br />

[左データ型]<br />

left object


第 5 章 <strong>圏</strong><strong>論</strong><strong>プログラミング</strong>言語<br />

ではい<strong>よ</strong>い<strong>よ</strong>, <strong>圏</strong><strong>論</strong>を使って<strong>プログラミング</strong>をしていきましょう. この<br />

章では, <strong>圏</strong><strong>論</strong><strong>プログラミング</strong>⾔言語を学び, この⾔言語を通して, <strong>圏</strong><strong>論</strong>を使っ<br />

てどの<strong>よ</strong>う<strong>に</strong><strong>プログラミング</strong>ができ<strong>る</strong>かを⾒見ていきます.<br />

<strong>圏</strong><strong>論</strong><strong>プログラミング</strong>言語<br />

<strong>圏</strong><strong>論</strong><strong>プログラミング</strong>言語 (Categorical Programming Language, CPL)<br />

は, 1987 年<strong>に</strong>萩野達也教授が発案した<strong>プログラミング</strong>⾔言語です. CPL では,<br />

プログラムを純粋<strong>に</strong><strong>圏</strong><strong>論</strong>の概念だけで記述します. 単純な⽂文法でありなが<br />

ら, ⾮非常<strong>に</strong>幅広い概念を記述できます.<br />

開発環境の導入<br />

CPL の実⾏行環境<strong>と</strong>して, 酒井政裕⽒氏<strong>に</strong><strong>よ</strong>って Haskell で実装されたイン<br />

タプリタがあります. これは Hackage から簡単<strong>に</strong>インストールできます.<br />

http://hackage.haskell.org/package/CPL<br />

まず, Haskell のコンパイラをインストールしておきましょう. Haskell<br />

Platform を導⼊入す<strong>る</strong>こ<strong>と</strong>をお勧めします.<br />

http://www.haskell.org/platform/<br />

Hackage のライブラリをインストールす<strong>る</strong><strong>に</strong>は, ⼿手動です<strong>る</strong>⽅方法もあり<br />

ますが, cabal <strong>と</strong>いうパッケージ管<strong>理</strong>システムを使うほうが便利です.<br />

cabal は Haskell Platform <strong>に</strong>標準装備されています.<br />

$ cabal install cpl<br />

した後, cpl コマンドでインタプリタを起動でき<strong>る</strong><strong>よ</strong>う<strong>に</strong>なります.<br />

(Windows の場合は C:¥Users¥***¥AppData¥Roaming¥cabal¥bin <strong>に</strong><br />

実⾏行ファイルが⼊入っています.)<br />

データ型の定義<br />

ではい<strong>よ</strong>い<strong>よ</strong>, CPL の⽂文法<strong>に</strong>ついて⾒見ていきましょう.<br />

CPL で定義す<strong>る</strong>データ型<strong>に</strong>は「左データ型」<strong>と</strong>「右データ型」があり, そ<br />

れぞれ以下の<strong>よ</strong>う<strong>に</strong>定義します.<br />

[左データ型]<br />

left object


す.<br />

なお, 右データ型<strong>に</strong>はもう⼀一種類の定義⽅方法がありますが, それ<strong>に</strong>つい<br />

ては後述します.<br />

さて, これから<strong>圏</strong><strong>論</strong>の⾔言葉を⽤用いてデータ型を定義していきます. その<br />

準備<strong>と</strong>して, 双代数<strong>と</strong>いう概念を定義します.<br />

双代数<br />

<strong>圏</strong> C,D <strong>と</strong>関⼿手 F,G:C→D があ<strong>る</strong><strong>と</strong>します.<br />

この<strong>と</strong>き, <strong>圏</strong> C の対象


なお, この<strong>圏</strong>は第 3 章のコラムで紹介したコンマ<strong>圏</strong>の特殊な場合です.


右データ型<strong>に</strong>おいては, G,H-終双代数が


直積は<br />

right object Prod(A,B) with pair is<br />

fst: Prod -> A<br />

snd: Prod -> B<br />

end object;<br />

<strong>と</strong>定義できます.


さて, ここでもう⼀一つ右データ型の定義の⽅方法を紹介します. 基本的<strong>に</strong><br />

はこれまで<strong>に</strong>紹介したもの<strong>と</strong>変わりません. 右データ型は


zero: 1 -> Nat<br />

succ: Nat -> Nat<br />

end object;<br />

<strong>と</strong>定義できます.


foldr


パラメータ化された⾃自然変換を取り扱うのです.<br />

た<strong>と</strong>えば<br />

Prod


element) は型 A の要素のうち, あ<strong>る</strong>「正規化 (regularize)」されたもの<br />

をいいます. 処<strong>理</strong>系は要素をデータ<strong>に</strong>正規化し終えたこ<strong>と</strong>をもって計算の<br />

終了を判断します.<br />

具体的<strong>に</strong>は CPL のデータ c は,


しかし, 冪対象を使えば<strong>よ</strong>り柔軟<strong>に</strong>関数を扱えます. 冪対象を使う上で<br />

のテクニックも後<strong>に</strong>紹介します.<br />

さて, やっ<strong>と</strong> CPL で<strong>プログラミング</strong>をす<strong>る</strong>準備ができました. CPL の開<br />

発環境の使い⽅方<strong>に</strong>慣れつつ, <strong>プログラミング</strong>をしていきましょう.<br />

開発環境の使い方<br />

まず, CPL を起動しましょう.<br />

Categorical Programming Language (Haskell version)<br />

version 0.0.6<br />

Type help for help<br />

cpl><br />

<strong>と</strong>表⽰示されます.<br />

edit <strong>と</strong>いうコマンドで編集モード<strong>に</strong>なります. た<strong>と</strong>えば<br />

cpl> edit<br />

| left object F(X) with P is<br />

| a:X->F<br />

| end object;<br />

<strong>と</strong>⼊入⼒力す<strong>る</strong><strong>と</strong><br />

left object F(+) is defined<br />

<strong>と</strong>いう出⼒力が返り, 無事データ型が定義できます. 出⼒力中の「+」は, そこ<br />

<strong>に</strong>⼊入<strong>る</strong>のが共変関⼿手であ<strong>る</strong>こ<strong>と</strong>を表します. ⽂文末のセミコロンを忘れない<br />

<strong>よ</strong>う<strong>に</strong>しましょう.<br />

直積を定義す<strong>る</strong><strong>と</strong><br />

right object Prod(+,+) is defined<br />

<strong>と</strong>表⽰示されます.<br />

また, 冪を定義す<strong>る</strong><strong>と</strong><br />

right object Exp(-,+) is defined<br />

<strong>と</strong>表⽰示されます. 「-」は逆<strong>に</strong>, 反変関⼿手であ<strong>る</strong>こ<strong>と</strong>を表します.<br />

ブール値<strong>と</strong>⾃自然数<strong>と</strong>リストも定義しておきます.<br />

...<br />

left object Bool is defined<br />

...<br />

left object Nat is defined<br />

...<br />

left object List(+) is defined<br />

射の定義も編集モードで書くこ<strong>と</strong>ができますが, 単⼀一⾏行で済むならば<br />

239


edit せず<strong>に</strong>書けます. (データ型も⼀一応, 単⼀一⾏行で済む場合はそのまま書<br />

けます. )<br />

cpl> let three = succ.succ.succ.zero<br />

three = succ.succ.succ.zero<br />

: 1 -> Nat<br />

cpl> let compose(f,g) = g.f<br />

f: *a -> *c g: *a -> *b<br />

-----------------------compose(f,g):<br />

*a -> *b<br />

*<strong>と</strong>いうプレフィックスは変数が型変数であ<strong>る</strong>こ<strong>と</strong>を表します.<br />

では, プログラムを実⾏行しましょう. 実⾏行す<strong>る</strong>プログラムは, 何らかの<br />

対象の要素でなければなりません. 何らかの対象の要素であ<strong>る</strong>プログラム<br />

をデータの形<strong>に</strong>直す, つまり正規化す<strong>る</strong>こ<strong>と</strong>こそが, CPL <strong>に</strong>おけ<strong>る</strong>プログ<br />

ラムの実⾏行なのです.<br />

そのため<strong>に</strong>は simp <strong>と</strong>いうコマンドを使います. simplification (簡約)<br />

の略です.<br />

まず⻑⾧長さ n の zero だけで埋められたリストを作<strong>る</strong>関数 zerolist を定義<br />

します.<br />

cpl> let zerolist =<br />

snd.pr(pair(zero,nil),pair(fst,cons))<br />

zerolist = snd.pr(pair(zero,nil),pair(fst,cons))<br />

そして, これ<strong>に</strong> three を適⽤用しましょう. 射の合成<strong>と</strong>いう形式で書くこ<strong>と</strong><br />

<strong>に</strong>注意してください.<br />

cpl> simp zerolist.three<br />

cons.pair(fst,cons).pair(fst,cons).pair(zero,nil)<br />

: 1 -> List(Nat)<br />

ちゃん<strong>と</strong>表⽰示されましたね. この形式でちゃん<strong>と</strong>したデータですが, なん<br />

だかリストらしく⾒見えません. <strong>よ</strong>り簡単な形<strong>に</strong>す<strong>る</strong>ため<strong>に</strong> full <strong>と</strong>いうコマ<br />

ンドを付け加えましょう.<br />

cpl> simp full zerolist.three<br />

cons.pair(zero,cons.<br />

pair(zero,cons.pair(zero,nil)))<br />

: 1 -> List(Nat)<br />

<strong>よ</strong>りリストらしくなりました. 基本的<strong>に</strong>は simp full のほうを使うこ<strong>と</strong>を<br />

240


おすすめします.<br />

なお, it <strong>と</strong>書く<strong>と</strong>直前<strong>に</strong>実⾏行したプログラム<strong>に</strong>展開されます.<br />

cpl> simp it<br />

cons.pair(fst,cons).pair(fst,cons).pair(zero,nil)<br />

: 1 -> List(Nat)<br />

せっかくなので, 中⾝身がどう動いてい<strong>る</strong>かを⾒見てみましょう. 次の<strong>よ</strong>う<br />

<strong>に</strong>す<strong>る</strong><strong>と</strong>, 処<strong>理</strong>系をトレースできます.<br />

cpl> set trace on<br />

cpl> simp full zerolist.three<br />

1[1]:three*I<br />

2[1]:succ.succ.succ.zero*I<br />

3[2]:succ.succ.zero*I<br />

4[3]:succ.zero*I<br />

5[4]:zero*I<br />

6[3]:succ*zero<br />

7[2]:succ*succ.zero<br />

8[1]:succ*succ.succ.zero<br />

9:zerolist*succ.succ.succ.zero<br />

10:snd.pr(pair(zero,nil),pair(fst,cons))*succ<br />

.succ.succ.zero<br />

(中略)<br />

46:cons*pair(zero,cons.<br />

pair(zero,cons.pair(zero,nil)))<br />

47:I*cons.pair(zero,cons.<br />

pair(zero,cons.pair(zero,nil)))<br />

cons.pair(zero,cons.<br />

pair(zero,cons.pair(zero,nil)))<br />

: 1 -> List(Nat)<br />

ずいぶん⻑⾧長い道のりですね. [n]の数字は解析の深さを表しています. 「f*d」<br />

はプログラム f <strong>に</strong>対してデータ d を適⽤用す<strong>る</strong>こ<strong>と</strong>を表しています. 詳しい<br />

241


仕組みは後述します.<br />

トレース機能をオフ<strong>に</strong>す<strong>る</strong>場合は set trace off すれば<strong>よ</strong>いです.<br />

ファイルから定義を読み込む<strong>に</strong>は load コマンドを使います.<br />

cpl> load mysourcecode.cpl<br />

なお, ファイル<strong>に</strong>書く際は, データ型の定義<strong>と</strong>射の定義<strong>と</strong>も<strong>に</strong>⽂文末のセ<br />

ミコロンを忘れない<strong>よ</strong>う<strong>に</strong>しましょう.<br />

それまでの定義をすべてリセットす<strong>る</strong><strong>に</strong>は reset <strong>と</strong>打ちます.<br />

show <strong>と</strong>いうコマンドでプログラムの型を得られます.<br />

cpl> show fst.pair(zero,nil)<br />

fst.pair(zero,nil)<br />

: 1 -> Nat<br />

また, show object <strong>と</strong>いうコマンドでデータ型<strong>に</strong>ついての詳しい情報が<br />

得られます.<br />

cpl> show object Prod<br />

right object Prod(+,+)<br />

- natural transformations:<br />

fst: Prod(*a,*b) -> *a<br />

snd: Prod(*a,*b) -> *b<br />

- factorizer:<br />

f0: *a -> *b f1: *a -> *c<br />

------------------------------<br />

pair(f0,f1): *a -> Prod(*b,*c)<br />

- equations:<br />

(REQ1): fst.pair(f0,f1)=f0<br />

(REQ2): snd.pair(f0,f1)=f1<br />

(RFEQ): Prod(f0,f1)=pair(f0.fst,f1.snd)<br />

(RCEQ): fst.g=f0 & snd.g=f1 => g=pair(f0,f1)<br />

- unconditioned: yes<br />

- productive: (yes,yes)<br />

最後<strong>に</strong>, 開発環境を終了す<strong>る</strong><strong>に</strong>は<br />

cpl> exit<br />

<strong>と</strong>しましょう.<br />

関数<strong>と</strong>の格闘<br />

CPL <strong>に</strong>おいては, 関数<strong>に</strong>はさまざまな表し⽅方があり, それぞれを上⼿手く<br />

利⽤用していくこ<strong>と</strong>が⼤大事です. きっちり<strong>理</strong>解しておきましょう.<br />

まず, ⼀一引数関数から考えていきます. A から B への関数の表し⽅方<strong>に</strong>は以<br />

242


下の3つがあります.<br />

1. 射


合は 1 の形式をも<strong>と</strong><strong>に</strong>して作ります.<br />

cpl> let not3 = curry(snd.Prod(id1,not1))<br />

not3 = curry(snd.Prod(id1,not1))<br />

: 1 -> Exp(Bool,Bool)<br />

cpl> simp eval.pair(not3,true)<br />

false<br />

: 1 -> Bool<br />

eval を使って関数適⽤用を⾏行うのが⾯面⽩白い<strong>と</strong>ころです. ちょっ<strong>と</strong>した⼯工夫<strong>と</strong><br />

して, 任意の射を冪対象<strong>に</strong>す<strong>る</strong>次の<strong>よ</strong>うな関数を作<strong>る</strong><strong>と</strong>いいでしょう.<br />

cpl> let toexp(f) = curry(snd.Prod(id1,f))<br />

toexp(f) = curry(snd.Prod(id1,f))<br />

f: *a -> *b<br />

------------------------toexp(f):<br />

1 -> Exp(*a,*b)<br />

次<strong>に</strong>, ⼆二引数関数を作っていきましょう. A×B から C への関数の表し⽅方<br />

は以下の4つがあります.<br />

1. 射


true.!<br />

: 1 -> Bool<br />

curry(snd) は素直<strong>に</strong>「第⼆二引数を取<strong>る</strong>」こ<strong>と</strong>だ<strong>と</strong><strong>理</strong>解してください.<br />

「!」でいったん終対象まで戻して情報をリセットしてからデータを書<br />

く, <strong>と</strong>いうのは頻繁<strong>に</strong>使う⼿手法なので覚えておきましょう. 計算結果<strong>に</strong>「!」<br />

が残って少し気持ち悪いかもしれませんが, これで問題ありません.<br />

1 の形式は 2 の形式をも<strong>と</strong><strong>に</strong>して作<strong>る</strong>こ<strong>と</strong>ができます.<br />

cpl> let or1 = eval.Prod(or2,I)<br />

or1 = eval.Prod(or2,I)<br />

: Prod(Bool,Bool) -> Bool<br />

cpl> simp full or1.pair(true,false)<br />

true.!<br />

: 1 -> Bool<br />

I の部分を変えれば第 2 引数を加⼯工しておくこ<strong>と</strong>ができます.<br />

普段使うのは 1 の形式なので, 慣れたら最初から 1 の形式で書きましょ<br />

う.<br />

cpl> let or1' =<br />

eval.Prod(if(curry(true.!),curry(snd)),I)<br />

or1' = eval.Prod(if(curry(true.!),curry(snd)),I)<br />

: Prod(Bool,Bool) -> Bool<br />

ちゃん<strong>と</strong>定義できましたね.<br />

次の関数は定義しておく<strong>と</strong><strong>よ</strong>く使います.<br />

cpl> let uncurry(f) = eval.Prod(f,I)<br />

次<strong>に</strong>, ⾜足し算を定義しましょう. これは少しだけ難しいです.<br />

まず, 4 の形式では次の<strong>よ</strong>う<strong>に</strong>します.<br />

cpl> let add4(m,n) = pr(n,succ).m<br />

add4(m,n) = pr(n,succ).m<br />

m: *a -> Nat n: 1 -> Nat<br />

------------------------add4(m,n):<br />

*a -> Nat<br />

これを 2 の形式では次の<strong>よ</strong>う<strong>に</strong>します.<br />

cpl> let add2 = pr(curry(snd),curry(succ.eval))<br />

add2 = pr(curry(snd),curry(succ.eval))<br />

: Nat -> Exp(Nat,Nat)<br />

curry(succ.eval)<strong>と</strong>いうのがポイントです. ここでは, succ は返り値<br />

を「加⼯工」してい<strong>る</strong><strong>と</strong>考えてください.<br />

最終的<strong>に</strong> 1 の形式では次の<strong>よ</strong>う<strong>に</strong>します.<br />

cpl> let add1 =<br />

245


uncurry(pr(curry(snd),curry(succ.eval)))<br />

add1 = uncurry(pr(curry(snd),curry(succ.eval)))<br />

: Prod(Nat,Nat) -> Nat<br />

順を追って考えていけば簡単ですね.<br />

楽しい<strong>プログラミング</strong><br />

では, CPL の<strong>よ</strong>りディープな世界<strong>に</strong>踏み込んでいきます. まず, 基本的な<br />

データ型をファイル<strong>に</strong>書きだしてしまいましょう.<br />

left object 0 with !!<br />

end object;<br />

right object 1 with !<br />

end object;<br />

right object Prod(A,B) with pair is<br />

fst: Prod -> A<br />

snd: Prod -> B<br />

end object;<br />

let swap = pair(snd,fst);<br />

left object Coprod(A,B) with case is<br />

inl: A -> Coprod<br />

inr: B -> Coprod<br />

end object;<br />

right object Exp(A,B) with curry is<br />

eval: Prod(Exp,A) -> B<br />

end object;<br />

let uncurry(f) = eval.Prod(f,I);<br />

left object Bool with if is<br />

true: 1 -> Bool<br />

false: 1 -> Bool<br />

end object;<br />

let id1 = fst.pair(I,true);<br />

let toexp(f) = curry(snd.Prod(id1,f));<br />

left object Nat with pr is<br />

zero: 1 -> Nat<br />

246


succ: Nat -> Nat<br />

end object;<br />

let one = succ.zero;<br />

let two = succ.one;<br />

let three = succ.two;<br />

left object List(A) with foldr is<br />

nil: 1 -> List<br />

cons: Prod(A,List) -> List<br />

end object;<br />

right object Inflist(A) with unfoldr is<br />

head': Inflist -> A<br />

tail': Inflist -> Inflist<br />

end object;<br />

定義の都合上, <strong>と</strong>ころどころ名前<strong>に</strong>「'」を付けます.<br />

こっそり swap も定義されています. また, ⾃自然数も名づけてあります.<br />

では, いろいろな関数を定義していきましょう.<br />

まずは, <strong>論</strong><strong>理</strong>値の関数です.<br />

let not = if(false,true);<br />

let equiv_(p,q) = if(q,not.q).p;<br />

let equiv = uncurry(if(curry(snd),curry(not.snd)));<br />

let or_(p,q) = if(true,q).p;<br />

let or = uncurry(if(curry(true.!),curry(snd)));<br />

let and_(p,q) = if(q,false).p;<br />

let and = uncurry(if(curry(snd),curry(false.!)));<br />

let xor = not.equiv;<br />

これは簡単ですね. なお,「_」が付いてい<strong>る</strong>のは説明のため<strong>に</strong>加えたポイ<br />

ントフリーでないバージョンです.<br />

次は, ⾃自然数の関数です.<br />

# pred.n : n-1<br />

let pred = pr(inl,inr.case(zero,succ));<br />

# add.pair(m,n) : m + n<br />

let add_(m,n) = pr(n,succ).m;<br />

let add = uncurry(pr(curry(snd),curry(succ.eval)));<br />

# sub.pair(m,n) : if m>=n then m-n else 0<br />

let sub_(m,n) = pr(inr.n,case(inl,pred)).m;<br />

let sub = uncurry(pr(curry(inr.snd),<br />

247


curry(case(inl,pred).eval))).swap;<br />

# mult.pair(m,n) : m*n<br />

let mult_(m,n) = pr(zero,add.pair(n.!,I)).m;<br />

let mult = uncurry(pr(curry(zero.!),<br />

curry(add.pair(eval,snd))));<br />

# fact.n : n*(n-1)*...*1<br />

let fact = fst.pr(pair(one,one),<br />

pair(mult.pair(snd,fst),succ.snd));<br />

let iszero = pr(true,if(false,false));<br />

# ge.pair(m,n) : m>=n<br />

let ge = case(false,true.!).sub;<br />

# le.pair(m,n) : m


foldr(nil,cons.Prod(eval.pair(f.!,I),I));<br />

⼀一気<strong>に</strong>ややこしくなってきました.<br />

uninlist は補助的な関数です. uninlist を使う<strong>と</strong> head <strong>と</strong> tail が簡<br />

単<strong>に</strong>記述でき<strong>る</strong>こ<strong>と</strong><strong>に</strong>注⽬目してください. 要はリストを分解してい<strong>る</strong>ので<br />

す. 詳しくは次の章で解説します.<br />

さて, concat <strong>と</strong> map をポイントフリー<strong>に</strong>したいですね. これがなかなか<br />

難しいのです. ⼀一歩ずつ考えていきましょう. まず, concat の定義は以下<br />

の<strong>よ</strong>うな形<strong>に</strong>な<strong>る</strong><strong>と</strong>考えられます.<br />

let concat = uncurry(foldr(curry(snd),curry(X)))<br />

この X の部分を考え<strong>る</strong><strong>と</strong>, X は以下の型を持つ<strong>と</strong>考えられます.<br />

Prod(Prod(*a,Exp(*b,List(*a))),*b) -> List(*a)<br />

ここから考え<strong>る</strong><strong>と</strong>, fst.fst で今問題<strong>と</strong>なってい<strong>る</strong>リストの要素,<br />

snd.fst が今まで作られた関数, snd が concat 関数全体の隠れた第 2 の<br />

引数であ<strong>る</strong><strong>と</strong>いえ<strong>る</strong>ので, X は<br />

cons.pair(fst.fst,eval.Prod(snd,I))<br />

<strong>と</strong>すれば<strong>よ</strong>く, 結局 concat は以下の<strong>よ</strong>うなもの<strong>に</strong>なります.<br />

let concat = uncurry(foldr(curry(snd),curry(<br />

cons.pair(fst.fst,eval.Prod(snd,I)))));<br />

振り返ってみれば意外<strong>と</strong>簡単ですね. 同様<strong>に</strong>して map は<br />

let map = uncurry(foldr(curry(nil.!),curry(<br />

cons.pair(eval.pair(snd,fst.fst),<br />

eval.Prod(snd,I))))).swap;<br />

<strong>と</strong>なります.<br />

reverse 関数も定義しておきましょう.<br />

let reverse = foldr(<br />

nil,concat.pair(snd,cons.pair(fst,nil.!)));<br />

次は, お待ちかねの無限リストの関数です.<br />

let cons' = unfoldr(fst,pair(head',tail').snd);<br />

let nth'_(a,n) = head'.pr(a,tail');<br />

let nth' = head'.<br />

uncurry(pr(curry(snd),curry(tail'.eval)));<br />

let repeat = unfoldr(I,I);<br />

let map' = unfoldr(<br />

eval.Prod(I,head'),Prod(I,tail'));<br />

let cycle = unfoldr(head,concat.pair(case(nil,I).<br />

tail,case(nil,singlelist).head));<br />

let zip = unfoldr(<br />

Prod(head',head'),Prod(tail',tail'));<br />

249


リストの関数<strong>よ</strong>りもむしろすっきりしていますね.<br />

無限リストを扱う関数であっても必ず有限時間内<strong>に</strong>計算は終了します.<br />

すべての計算が有限時間内<strong>に</strong>停⽌止す<strong>る</strong>こ<strong>と</strong>は CPL の⼤大きな特徴です. (つま<br />

り CPL はチューリング不完全です.) これはプログラムの安全性<strong>と</strong>いう観<br />

点からも重要であ<strong>る</strong><strong>と</strong>いえます.<br />

ここまでで紹介したこ<strong>と</strong>を応⽤用して, ぜひ, さまざまな<strong>プログラミング</strong><br />

を楽しんでくださいね.<br />

データ型の整<strong>理</strong><br />

CPL のデータ型を<strong>よ</strong>く考えてみ<strong>る</strong><strong>と</strong>, あらゆ<strong>る</strong>データ型は実質的<strong>に</strong>始対<br />

象・終対象・直積・直和・冪だけでできてい<strong>る</strong>こ<strong>と</strong>がわかります.<br />

左データ<strong>に</strong>おいて<br />

left object


<strong>と</strong>同じです.<br />

た<strong>と</strong>えば⾃自然数・リスト・無限リストの定義はそれぞれ<br />

left object Nat with pr is<br />

innat: Coprod(1,Nat) -> Nat<br />

end object;<br />

left object List(A) with foldr is<br />

inlist: Coprod(1,Prod(A,List)) -> List<br />

end object;<br />

right object Inflist(A) with unfoldr is<br />

outinflist: Inflist -> Prod(A,Inflist)<br />

end object;<br />

<strong>と</strong>書き換えられます. CPL で定義でき<strong>る</strong>データ型は意外<strong>と</strong>単純なのです.<br />

<strong>よ</strong>り多くのデータ型<br />

<strong>よ</strong>りマニアックなデータ型の世界へ⾜足を踏み⼊入れましょう.<br />

余自然数 (conatural number) は<br />

right object Conat with pcr is<br />

pred': Conat -> Coprod(1,Conat)<br />

end object;<br />

<strong>と</strong>定義できます. ⾃自然数の双対<strong>に</strong>なっています.<br />

余⾃自然数は, ⾃自然数<strong>に</strong>無限⼤大を加えたものです. これでいてちゃん<strong>と</strong>い<br />

ろいろな演算ができます.<br />

pred’は以下を満たす射です.<br />

pred ! ∘ 0 = inl<br />

pred ! ∘ (


let three' = toconat.three;<br />

さらっ<strong>と</strong>無限を扱え<strong>る</strong>のが素晴らしいですね.<br />

では, 演算を定義しましょう.<br />

let succ' = pcr(Coprod(I,pred'));<br />

let add' = pcr(uncurry(case(<br />

toexp(Coprod(I,pair(zero'.!,I)).pred'),<br />

curry(inr))).Prod(pred',I));<br />

let sub' = uncurry(pr(curry(inr.snd),<br />

curry(case(inl,pred').eval))).swap;<br />

let ge' = case(false,true.!).sub';<br />

let gt' = ge'.Prod(I,succ);<br />

let le' = not.gt';<br />

let eq' = and.pair(ge',le');<br />

マニアックな感じがいいですね. sub’以降の関数は余⾃自然数<strong>と</strong>⾃自然数を引<br />

数<strong>と</strong>します. 必ず有限時間内で終わ<strong>る</strong><strong>よ</strong>うな計算しかできないので, 余⾃自<br />

然数から余⾃自然数を引く関数は定義できないのです.<br />

余リスト (colist) は<br />

right object Colist(A) with unfoldr’ is<br />

outcolist: Colist -> Coprod(1,Prod(A,Colist))<br />

end object;<br />

<strong>と</strong>定義できます. リストの双対<strong>に</strong>なっています.<br />

余リストは要素数が有限<strong>に</strong>も無限<strong>に</strong>もなりえます. 絶対<strong>に</strong>有限であ<strong>る</strong>リ<br />

スト<strong>と</strong>絶対<strong>に</strong>無限であ<strong>る</strong>無限リストの間の<strong>よ</strong>うなものです.<br />

let length' = pcr(Coprod(I,snd).outcolist);<br />

let fromlist_tocolist = unfoldr'(uninlist);<br />

let frominflist_tocolist =<br />

unfoldr'(inr.pair(head',tail'));<br />

let unoutcolist = unfoldr'(<br />

Coprod(I,Prod(I,outcolist)));<br />

let nil'' = unoutcolist.inl;<br />

let cons'' = unoutcolist.inr;<br />

let singlelist' = cons''.pair(I,nil''.!);<br />

unoutcolist は既出の uninlist の双対で, 余リストを構成す<strong>る</strong>こ<strong>と</strong>を意<br />

味します. 詳しいこ<strong>と</strong>は次の章まで待ってください.<br />

リスト<strong>と</strong>無限リストがわかっていれば余リストは普通<strong>に</strong>扱え<strong>る</strong>はずな<br />

ので, 頑張ってみてください.<br />

これらのほか<strong>に</strong>, いくらでもデータ構造は考えられます.<br />

252


た<strong>と</strong>えば, 二分木 (binary tree) は<br />

left object Binary(A) with foldbinary is<br />

leaf: A -> Binary<br />

branch: Prod(Binary, Binary) -> Binary<br />

end object;<br />

<strong>と</strong>定義できます.<br />

また, 多分木 (rose tree, multi-way tree) は<br />

left object Rose(A) with foldrose is<br />

leafr: A -> Rose<br />

branchr: List(A) -> Rose<br />

end object;<br />

<strong>と</strong>定義できます.<br />

CPL でぜひいろいろ遊んでみてくださいね.<br />

どうして動くのか<br />

CPL <strong>に</strong>おけ<strong>る</strong>プログラムの実⾏行, つまり正規化の⽅方法を紹介します.<br />

プログラムの実⾏行<strong>に</strong>は simp <strong>と</strong> simp full の⼆二種類がありますが, まず<br />

simp から紹介していきます.<br />

プログラム e <strong>と</strong>データ c があ<strong>る</strong><strong>と</strong>き, e <strong>に</strong> c を与え<strong>る</strong>こ<strong>と</strong>を


[L-‐‑‒FACT]


[FULL-‐‑‒L-‐‑‒FACT]


第 6 章 <strong>圏</strong><strong>論</strong><strong>と</strong>再帰<br />

<strong>圏</strong><strong>論</strong>の<strong>理</strong><strong>論</strong>的な強⼒力さを味わっていきましょう. この章では, プログラ<br />

ミング<strong>に</strong>おいて頻出す<strong>る</strong>再帰構造<strong>と</strong>再帰処<strong>理</strong>を, <strong>圏</strong><strong>論</strong>を⽤用いて綺麗<strong>に</strong>表現<br />

でき<strong>る</strong>こ<strong>と</strong>を⽰示します.<br />

代数<br />

F-代数 (F-algebra) は F,I-双代数<strong>に</strong>あた<strong>る</strong>ものです.<br />

代数の<strong>圏</strong><br />

F-代数の<strong>圏</strong>は F,I-双代数の<strong>圏</strong><strong>に</strong>あた<strong>る</strong>もので,


対です.<br />

余代数の<strong>圏</strong><br />

G-余代数の<strong>圏</strong>は, I,G-双代数の<strong>圏</strong><strong>に</strong>あた<strong>る</strong>もので,


型<strong>に</strong>おいては G,H-終双代数から, それぞれ定義されていました. 詳しくは<br />

5 章を参照してください.<br />

ここで, 左データ型<strong>に</strong>おいて


cata-CHARN 3 :


∵ in ∘


In が⼊入ってい<strong>る</strong>ので少しややこしいですが, 数は次の<strong>よ</strong>う<strong>に</strong>定義され<br />

ます.<br />

zero = In Zero<br />

one = In (Succ zero)<br />

two = In (Succ one)<br />

リスト<strong>に</strong>ついては⼆二引数関⼿手 L(A,X)=1+A×X を考えます. 対象 A を部<br />

分適⽤用した関⼿手


add x y = cata phi x<br />

where phi Zero = y<br />

phi (Succ r) = succN r<br />

-- add zeroN y = y<br />

-- add (succN x) y = succN (add x y)<br />

mul :: Nat -> Nat -> Nat<br />

mul x y = cata phi x<br />

where phi Zero = zeroN<br />

phi (Succ r) = add r y<br />

-- mul zeroN y = zeroN<br />

-- mul (succN x) y = add (mul x y) y<br />

intToNat はカタモーフィズムで書けないので, 普通の再帰で書きました.<br />

ちょっ<strong>と</strong>不思議な形式<strong>に</strong>⾒見え<strong>る</strong>かもしれませんが, コメントを⾒見ながら感<br />

覚をつかんでください. あ<strong>と</strong>は CPL の<strong>と</strong>き<strong>と</strong>同じ<strong>よ</strong>う<strong>に</strong>でき<strong>る</strong>はずです.<br />

この内容を CPL で書きなおしてみても⾯面⽩白い<strong>と</strong>思います.<br />

次は, リストの関数です.<br />

nilL = In Nil<br />

consL x xs = In (Cons x xs)<br />

fromList :: List a -> [a]<br />

fromList xs = cata phi xs<br />

where phi Nil = []<br />

phi (Cons x r) = x:r<br />

-- fromList nilL = []<br />

-- fromList (consL x xs') = x:fromList xs'<br />

toList :: [a] -> List a<br />

toList [] = nilL<br />

toList (x:xs) = consL x (toList xs)<br />

lengthL :: List a -> Nat<br />

lengthL xs = cata phi xs<br />

where phi Nil = zeroN<br />

phi (Cons _ r) = succN r<br />

-- lengthL nilL = zeroN<br />

-- lengthL (consL _ xs) = succN (lengthL xs)<br />

toList も普通の再帰で書きました.<br />

262


補⾜足しておく<strong>と</strong>, 実は in !! =


mapL :: (a -> b) -> List a -> List b<br />

mapL f = cata (In.(fbimap f id))<br />

Haskell の標準ライブラリ<strong>に</strong>は標準では双関⼿手の型クラスがないので,<br />

Bifunctor <strong>と</strong>いう型クラスを作りました. map の関数の定義がかなり綺麗<br />

<strong>に</strong>なりましたね.<br />

アナモーフィズム<br />


ana-SELF はアナモーフィズムの再帰処<strong>理</strong>の全てです.<br />

<strong>と</strong>りあえず, Haskell で書いてみましょう.<br />

newtype Nu f = Wrap (f (Nu f))<br />

out :: Nu f -> f (Nu f)<br />

out (Wrap x) = x<br />

ana :: Functor f => (a -> f a) -> a -> Nu f<br />

ana phi = Wrap . fmap (ana phi) . phi<br />

type Conat = Nu N<br />

type Colist a = Nu (L a)<br />

余⾃自然数 (“Conat”) は無限⼤大を含む⾃自然数で, 余リスト (“Colist”) は<br />

要素数が有限<strong>に</strong>も無限<strong>に</strong>もなりう<strong>る</strong>リストです. 余リスト<strong>と</strong>いっても<br />

Haskell の標準のリストも余リストなので恐れ<strong>る</strong>こ<strong>と</strong>はありません.<br />

まずは余⾃自然数を使ってみましょう.<br />

zeroCN = Wrap Zero<br />

succCN n = Wrap (Succ n)<br />

intToConat :: Int -> Conat<br />

intToConat n = ana phi n<br />

where phi 0 = Zero<br />

phi n’ = Succ (n’-1)<br />

-- intToConat 0 = zeroCN<br />

-- intToConat n = succCN (intToConat (n-1))<br />

infinity :: Conat<br />

infinity = intToConat (-1)<br />

conatToInt :: Conat -> Int<br />

conatToInt (Wrap (Succ n)) = 1 + conatToInt n<br />

conatToInt (Wrap Zero) = 0<br />

add' :: Conat -> Conat -> Conat<br />

add' x y = ana phi (x,y)<br />

where phi (Wrap Zero, Wrap Zero) = Zero<br />

phi (Wrap(Succ x'), y) = Succ (x',y)<br />

phi (x, Wrap(Succ y')) = Succ (x,y')<br />

-- add' zeroCN zeroCN = zeroCN<br />

-- add' (succCN x') y = succCN (add' x' y)<br />

-- add' x (succCN y') = succCN (add' x y')<br />

265


conatToInt はアナモーフィズムを使って書けないので普通の再帰で書き<br />

ました.<br />

次は余リストの関数です.<br />

nilCL = Wrap Nil<br />

consCL x xs = Wrap (Cons x xs)<br />

toColist :: [a] -> Colist a<br />

toColist xs = ana phi xs<br />

where phi [] = Nil<br />

phi (x:xs') = Cons x xs'<br />

-- toColist [] = nilCL<br />

-- toColist x:xs = consCL x (toColist xs)<br />

fromColist :: Colist a -> [a]<br />

fromColist (Wrap Nil) = []<br />

fromColist (Wrap(Cons x xs)) = x:fromColist xs<br />

decleasingSeq :: Conat -> Colist Conat<br />

decleasingSeq n = ana phi n<br />

where phi (Wrap Zero) = Nil<br />

phi (Wrap (Succ n')) = Cons n' n'<br />

-- decleasingSeq zeroCN = nilCL<br />

-- decleasingSeq (succCN n) =<br />

consCL n (decleasingSeq n)<br />

-- decleasingSeq n = [n-1,n-2,n-3,...,0]<br />

fromColist も普通の再帰で書きました.<br />

なお, 5 章で out-inv-DEF を使っていたのは以下の関数です.<br />

let cons' = unfoldr(<br />

fst,pair(head',tail').snd);<br />

let succ' = pcr(Coprod(I,pred'));<br />

let unoutcolist = unfoldr'(<br />

Coprod(I,Prod(I,outcolist)));<br />

また, data-map-DEF の<strong>と</strong>き<strong>と</strong>同様<strong>に</strong>, 関数


有限<strong>と</strong>無限<br />

mapCL :: (a -> b) -> Colist a -> Colist b<br />

mapCL f = ana ((fbimap f id).out)<br />

ここまでの説明で気づいた⽅方もい<strong>る</strong>かもしれませんが, Mu <strong>と</strong> Nu は実質<br />

的<strong>に</strong>同じ定義がなされています.<br />

newtype Mu f = In (f (Mu f))<br />

unIn :: Mu f -> f (Mu f)<br />

unIn (In x) = x<br />

newtype Nu f = Wrap (f (Nu f))<br />

out :: Nu f -> f (Nu f)<br />

out (Wrap x) = x<br />

名前が変わってい<strong>る</strong><strong>に</strong>すぎません. 実際, Haskell <strong>に</strong>おいては, 両者は同⼀一<br />

視されます. CPL <strong>と</strong>は事情が違うのです. CPL では計算が有限時間で終わ<br />

<strong>る</strong>こ<strong>と</strong>が保障されていましたが, これは有限の型<strong>と</strong>無限の型を厳密<strong>に</strong>区別<br />

してい<strong>る</strong>ため<strong>に</strong>実現されています. この区別が明確でない (例えば, 有限<br />

リスト<strong>と</strong>無限リストが同じ型 [] であ<strong>る</strong>) Haskell ではその<strong>よ</strong>うな保証は<br />

されていません.<br />

Haskell ではリストは無限リスト<strong>に</strong>なりえ<strong>る</strong>し, ⾃自然数は無限⼤大<strong>に</strong>なり<br />

えます. ただ, 無限リストや無限⼤大を作り出す<strong>に</strong>は, カタモーフィズム<strong>と</strong><br />

は違う「普通の再帰」を⽤用いなければなりません. 以前 intToNat <strong>と</strong>いう<br />

関数を定義しましたが, あの<strong>よ</strong>うな関数です. た<strong>と</strong>えば「intToNat -1」<br />

<strong>と</strong>書く<strong>と</strong>容易<strong>に</strong>無限⼤大が得られます.<br />

ハイロモーフィズム<br />

F-始代数<strong>と</strong> F-終余代数が同じ<strong>と</strong>き, アナモーフィズム


添え字は適宜省略します.<br />

定義をま<strong>と</strong>め<strong>る</strong><strong>と</strong>この<strong>よ</strong>う<strong>に</strong>なります.<br />

hylo-DEF:


ます.<br />

プログラムの⾼高速化技術の⼀一つ<strong>と</strong>して「融合変換 (program fusion)」<br />

<strong>と</strong>いうものがあります. これは, 関数 f,g を合成した関数


para-FUSION:


アポモーフィズム (apomorphism 9 ) はパラモーフィズムの双対です. し<br />

かし, 感覚的<strong>に</strong>は意味が⼤大きく変わります. 「再帰を終え<strong>る</strong>こ<strong>と</strong>ができ<strong>る</strong>」<br />

<strong>と</strong>いう感じ<strong>に</strong>なります.<br />


join f g (Left x) = f x<br />

join f g (Right y) = g y<br />

Either a b -> c<br />

apo :: Functor f =><br />

(a -> f (Either a (Nu f))) -> a -> Nu f<br />

apo phi = Wrap . fmap (join (apo phi) id) . phi<br />

さっそくアポモーフィズムを使っていきましょう.<br />

insertCL :: Ord a =><br />

a -> Colist a -> Colist a<br />

insertCL k xs = apo phi xs<br />

where phi (Wrap Nil) = Cons k (Right nilCL)<br />

phi (Wrap (Cons x xs'))<br />

| x < k = Cons x (Left xs')<br />

| otherwise =<br />

Cons k (Right (consCL x xs'))<br />

-- insertCL k nilCL = Cons k nilCL<br />

-- insertCL k (consCL x xs')<br />

-- | x < k = consCL x (insertCL k xs')<br />

-- | otherwise = consCL k (consCL x xs')<br />

appendCL :: Colist a -> Colist a -> Colist a<br />

appendCL xs ys = apo phi (xs,ys)<br />

where phi (Wrap Nil, Wrap Nil) = Nil<br />

phi (Wrap Nil, Wrap (Cons y ys')) =<br />

Cons y (Right ys')<br />

phi (Wrap (Cons x xs'), ys') =<br />

Cons x (Left (xs',ys'))<br />

-- appendCL nilCL nilCL = nilCL<br />

-- appendCL nilCL (consCL y ys') = consCL y ys'<br />

-- appendCL (consCL x xs') ys' =<br />

-- consCL x (appendCL xs' ys')<br />

感覚をつかめば簡単ですね.<br />

お疲れ様でした. これで再帰構造を扱うのは終わりです. あ<strong>と</strong>は⾃自分で<br />

いろいろ実験したり勉強したりしてください.<br />

272


第 7 章 モナド<strong>と</strong>クライスリ<strong>圏</strong><br />

モナドは Haskell <strong>と</strong>切っても切れない関係<strong>に</strong>あ<strong>る</strong>ものです. モナドが単<br />

純な仕組みであ<strong>る</strong>こ<strong>と</strong>は, Haskeller なら<strong>理</strong>解してい<strong>る</strong>こ<strong>と</strong>だ<strong>と</strong>思います.<br />

しかしながら, その<strong>理</strong><strong>論</strong>的な側⾯面<strong>と</strong>な<strong>る</strong><strong>と</strong>, 具体的なモナドを考え<strong>る</strong>だ<br />

けでは<strong>理</strong>解しづらいこ<strong>と</strong>もあ<strong>る</strong>でしょう. この章ではプログラム<strong>に</strong><strong>よ</strong><strong>る</strong>解<br />

説を交えつつ, <strong>圏</strong><strong>論</strong>からモナド<strong>に</strong>アプローチしていきます.<br />

モナド<br />

<strong>圏</strong> C 上のモナド (monad)


なってい<strong>る</strong>もの<strong>と</strong>します. なお, ⼀一般<strong>に</strong>モナド<strong>に</strong>関す<strong>る</strong>関⼿手は Haskell <strong>に</strong><br />

おいて次の<strong>よ</strong>う<strong>に</strong>定義できます.<br />

fmap f x = x >>= (return.f)<br />

また, join <strong>と</strong>いう関数があります.<br />

join :: (Monad m) => m (m a) -> m a<br />

join x = x >>= id<br />

実はηが return, μが join <strong>に</strong>あたります. return <strong>と</strong> join を⽤用いて改めて<br />

結合律<strong>と</strong>左・右単位元律を表す<strong>と</strong>以下の<strong>よ</strong>う<strong>に</strong>なります.<br />

join . join == join . fmap join<br />

join . return == join . fmap return == id<br />

ここで, ⾃自然変換の⽔水平合成の定義<strong>よ</strong>り


<strong>圏</strong> C 上のクライスリ三つ組 (Kleisli triple)


・副作⽤用のあ<strong>る</strong>計算(≒State Monad, IO Monad):


コラム <strong>圏</strong><strong>論</strong><strong>と</strong>哲学<br />

<strong>圏</strong><strong>論</strong>の⽤用語<strong>に</strong>は哲学⽤用語<strong>と</strong>同じものがいくつかあります. 偶然の⼀一<br />

致もあ<strong>る</strong>かもしれませんが, 哲学<strong>に</strong>影響された可能性も⼤大い<strong>に</strong>あ<strong>る</strong>で<br />

しょう.<br />

そもそも「<strong>圏</strong> (category)」⾃自体が哲学では⼀一般<strong>に</strong>「範疇」<strong>と</strong>か「カ<br />

テゴリー」<strong>と</strong>訳され<strong>る</strong>概念で, ⼈人間のなしう<strong>る</strong>「分類」のこ<strong>と</strong>をいい<br />

ます. 例えばアリストテレス (Aristotélēs, 前 384-‐‑‒前 322) は存在<br />

者を「実体・量・質・関係・場所・時間・位置・所有・能動・受動」<br />

<strong>と</strong>いう 10 の カテゴリー<strong>に</strong> 分類し , またイマヌエル・カント<br />

(Immanuel Kant, 1724-‐‑‒1804) はその主著『純粋<strong>理</strong>性批判』<strong>に</strong>おいて<br />

⼈人間の知性のうち<strong>に</strong>「量・質・関係・様態」<strong>と</strong>いうカテゴリーが備わ<br />

ってい<strong>る</strong>こ<strong>と</strong>を主張しました.<br />

また, 前の章で扱った「ハイロモーフィズム」は「質料形相<strong>論</strong>」<strong>と</strong><br />

訳され<strong>る</strong>概念で, 元は<strong>と</strong>いえばこの⽤用語もやはりアリストテレスの形<br />

⽽而上学<strong>に</strong>由来します.<br />

なぜこれほど哲学由来<strong>と</strong>思われ<strong>る</strong>語が多いのか<strong>と</strong>いう<strong>と</strong>, それは<strong>圏</strong><br />

<strong>論</strong>が⼀一般的な概念を記述す<strong>る</strong>こ<strong>と</strong>を⽬目指してい<strong>る</strong>からだ<strong>と</strong>思います.<br />

哲学⾃自体<strong>に</strong>おけ<strong>る</strong><strong>圏</strong><strong>論</strong>の利⽤用はまだ黎明期であ<strong>る</strong><strong>と</strong>⾔言え<strong>る</strong>でしょ<br />

う. しかし, 抽象的な概念を語<strong>る</strong>の<strong>に</strong><strong>圏</strong><strong>論</strong>の「⾔言葉」は役⽴立つので, こ<br />

れから少なからず使われていくこ<strong>と</strong><strong>に</strong>な<strong>る</strong><strong>と</strong>思います. <strong>圏</strong><strong>論</strong>が⼀一般<strong>に</strong><br />

広まって, さまざまな<strong>と</strong>ころで「道具」<strong>と</strong>して認識され<strong>る</strong><strong>よ</strong>う<strong>に</strong>な<strong>る</strong><br />

<strong>と</strong>いい<strong>と</strong>思います.<br />

277


第Ⅲ部<br />

<strong>圏</strong><strong>論</strong><strong>と</strong><strong>論</strong><strong>理</strong>学<br />

278


第 8 章 <strong>論</strong><strong>理</strong>の基礎<br />

この章では, <strong>論</strong><strong>理</strong>学の基本的な部分をもう少し詳しく扱います. 特<strong>に</strong>⼀一章<br />

で扱った⼀一階の命題<strong>論</strong><strong>理</strong><strong>と</strong>述語<strong>論</strong><strong>理</strong><strong>に</strong>ついて, 具体的<strong>に</strong>どの<strong>よ</strong>うな体系か<br />

ら構築でき<strong>る</strong>のかを⽰示します.<br />

<strong>論</strong><strong>理</strong><strong>と</strong>は何か (再考)<br />

第 1 章でわたしたちは「<strong>論</strong><strong>理</strong>学は思考の法則<strong>に</strong>関す<strong>る</strong>学問であ<strong>る</strong>」<strong>と</strong>書<br />

きました. ここで念頭<strong>に</strong>あったのは, 数学<strong>に</strong>おけ<strong>る</strong>証明 (proof) です. た<br />

<strong>と</strong>えばわたしたちは,<br />


<strong>る</strong>はずです:


零項真<strong>理</strong>関数 true, false<br />

⼀一項真<strong>理</strong>関数 ¬<br />

⼆二項真<strong>理</strong>関数 ∧,∨, →, ↔<br />

統辞<strong>論</strong>の形式<strong>に</strong>触れ<strong>る</strong>前<strong>に</strong>, ¬,∧,∨, →, ↔ の結合性<strong>に</strong>ついて注意してお<br />

きます. 結合の強さは ¬ / ∧,∨ / → / ↔ の順で, 左ほど強い結合性を持ち<br />

ます. また, → は右結合です. すなわち,


真偽を “true” <strong>と</strong> “false” <strong>と</strong>いう値で表します. C ⾔言語なら, 0 == false<br />

で 1 == true です. その<strong>よ</strong>う<strong>に</strong>取り決めた上で, C の処<strong>理</strong>系は “3 + 5<br />

== 8; // true” など<strong>と</strong>解釈でき<strong>る</strong>わけです. (もちろん真/偽を数値<strong>と</strong>同⼀一<br />

視しない<strong>プログラミング</strong>⾔言語もあり, その場合は true/false ⾃自体が別の<br />

データ型の値<strong>と</strong>して定義され<strong>る</strong>でしょう.)<br />

この<strong>よ</strong>うな考え⽅方<strong>に</strong><strong>よ</strong>って, わたしたちは「真偽」<strong>と</strong>いう概念を明確<strong>に</strong>す<br />

<strong>る</strong>こ<strong>と</strong>ができます. モデル<strong>論</strong>的意味<strong>論</strong><strong>に</strong>おいては, 「命題がどの<strong>よ</strong>うな場合<br />

<strong>に</strong>真/偽であ<strong>る</strong>か」<strong>と</strong>いう問いを「領域 (domain)」<strong>と</strong>いう集合<strong>と</strong>「解釈<br />

(interpretation)」<strong>と</strong>いう写像<strong>に</strong>置き換え, 形式的<strong>に</strong>定義します.<br />

「真偽」<strong>に</strong>あた<strong>る</strong>ものは真<strong>理</strong>値であ<strong>る</strong>領域です. これを次の<strong>よ</strong>う<strong>に</strong>定義し<br />

ましょう:<br />

D ! ∶= {1,0}<br />

C ⾔言語<strong>と</strong>同じで, 1 が真を, 0 が偽を表します. それ以外の真<strong>理</strong>値は存在し<br />

ません.<br />

解釈は「<strong>論</strong><strong>理</strong>式の集合」から D ! への写像です. あ<strong>る</strong>解釈 I のも<strong>と</strong>で<strong>論</strong><br />

<strong>理</strong>式


∧ ! ∶=<br />

→ ! ∶=<br />

1, 1 ↦ 1<br />

1, 0 ↦ 0<br />

0, 1 ↦ 0<br />

0, 0 ↦ 0<br />

(1, 1) ↦ 1<br />

1, 0 ↦ 0<br />

0, 1 ↦ 1<br />

(0, 0) ↦ 1<br />

∨ ! ∶=<br />

↔ ! ∶=<br />

1, 1 ↦ 1<br />

1, 0 ↦ 1<br />

0, 1 ↦ 1<br />

0, 0 ↦ 0<br />

(1, 1) ↦ 1<br />

1, 0 ↦ 0<br />

0, 1 ↦ 1<br />

(0, 0) ↦ 1<br />

解釈の定義は以上です. さて, この意味<strong>論</strong><strong>に</strong>おいて「妥当な推<strong>論</strong>」<strong>と</strong>は何<br />

かを考えましょう. 先ほどの条件をモデル<strong>論</strong>的意味<strong>論</strong><strong>に</strong>当てはめ<strong>る</strong><strong>と</strong>, 推<br />

<strong>論</strong>


・ ⊨


零項真<strong>理</strong>関数 true, false<br />

⼀一項真<strong>理</strong>関数 ¬<br />

⼆二項真<strong>理</strong>関数 ∧,∨, →, ↔<br />

量化⼦子 ∀, ∃<br />

「名前」<strong>と</strong>「述語」, 「変項」,「量化⼦子」の意味は 1 章で説明した通り<br />

です. また, 命題<strong>論</strong><strong>理</strong><strong>と</strong>同様<strong>に</strong>, n 項真<strong>理</strong>関数が定義されます.<br />

1 章で「関数」<strong>と</strong>呼んでいたものは, 真<strong>理</strong>関数<strong>と</strong>区別す<strong>る</strong>ため, ここでは<br />

「演算⼦子」<strong>と</strong>呼びます. 「〜~の⼆二乗」, 「×」などは全て演算⼦子です.演算⼦子<br />

は取<strong>る</strong>項の個数<strong>に</strong>応じて n 項演算子 (n-place operator) <strong>と</strong>呼ばれます.<br />

n 項述語<strong>に</strong> n タプル<strong>と</strong>して与えられ<strong>る</strong>のは項 (term) です. 項は以下の規<br />

則<strong>に</strong><strong>よ</strong>って定義されます.<br />

1.


<strong>論</strong><strong>理</strong>式


複合<strong>論</strong><strong>理</strong>式


以上の M, g が与えられれば, 解釈 I は⼀一意<strong>に</strong>定まります.<br />

<strong>論</strong><strong>理</strong>式


はないか<strong>と</strong>考えられ<strong>る</strong>のです. た<strong>と</strong>え集合概念以外のモデルを⽤用いた<strong>と</strong>し<br />

ても, どのみち<strong>論</strong><strong>理</strong>の体系はそれ<strong>に</strong>依存した形で相対的<strong>に</strong>妥当性を保証さ<br />

れ<strong>る</strong>のみ<strong>に</strong>なります.<br />

そこで本節では, モデル<strong>論</strong>的意味<strong>論</strong><strong>に</strong>換えて, 「証明<strong>論</strong> (proof theory)<br />

的意味<strong>論</strong>」を考えます. 証明<strong>論</strong>的意味<strong>論</strong><strong>に</strong><strong>よ</strong>れば, 「集合」概念<strong>に</strong>依存せず,<br />

<strong>論</strong><strong>理</strong>の⾔言葉だけで<strong>論</strong><strong>理</strong>を定義でき<strong>る</strong>からです.<br />

証明<strong>論</strong>では, 解釈<strong>に</strong><strong>よ</strong>って推<strong>論</strong>の妥当性を定義す<strong>る</strong>代わり<strong>に</strong>, 推<strong>論</strong><strong>に</strong>形<br />

式的な規則を与え<strong>る</strong>こ<strong>と</strong>で命題が「証明可能」であ<strong>る</strong>こ<strong>と</strong>を⽰示します.<br />

例えば, ¬(


1.


3.


(CE)


前提 Γ から<strong>論</strong><strong>理</strong>式


⼀一般的<strong>に</strong>, <strong>論</strong><strong>理</strong>式


⼀一般的<strong>に</strong>, <strong>論</strong><strong>理</strong>式


ベルト流証明<strong>論</strong><strong>と</strong>⾃自然演繹を「直接<strong>に</strong>」⽐比較す<strong>る</strong>こ<strong>と</strong>ができ<strong>る</strong><strong>よ</strong>う<strong>に</strong>なりま<br />

す.<br />

296


第 9 章 <strong>論</strong><strong>理</strong><strong>と</strong>計算<strong>と</strong><strong>圏</strong><br />

この章では, <strong>論</strong><strong>理</strong><strong>と</strong>計算, お<strong>よ</strong>び<strong>圏</strong>の間<strong>に</strong>あ<strong>る</strong>関係<strong>に</strong>ついて⾒見ていきま<br />

す. 少し哲学的な内容<strong>に</strong>踏み込むので, 他の章<strong>と</strong>は⽑毛⾊色の違った内容<strong>に</strong>な<br />

<strong>る</strong>かもしれません. しかし, これらの関係はプログラムの (プログラマー<br />

の普段の⾒見⽅方<strong>と</strong>はおそらく異な<strong>る</strong>) <strong>理</strong><strong>論</strong>的背景を<strong>理</strong>解す<strong>る</strong>⼀一端<strong>と</strong>な<strong>る</strong>部分<br />

なので, 読んでおいて損はないでしょう.<br />

まず直観主義<strong>と</strong>呼ばれ<strong>る</strong>数学的⽴立場<strong>に</strong>ついて紹介し, 直観主義の視点か<br />

ら<strong>論</strong><strong>理</strong><strong>と</strong>計算の間<strong>に</strong>⾃自然な対応が⾒見出せ<strong>る</strong>こ<strong>と</strong>を確かめます. 続いて, そ<br />

の対応を<strong>圏</strong><strong>論</strong>の⾔言葉で書きなおしてみます.<br />

直観主義<strong>論</strong><strong>理</strong><br />

直観主義<strong>論</strong><strong>理</strong>は, 前章で⾒見た<strong>よ</strong>う<strong>に</strong>, 古典<strong>論</strong><strong>理</strong>から排中律を除いた体系<br />

でした. しかし, なぜこれが「直観主義」<strong>論</strong><strong>理</strong><strong>と</strong>呼ばれ<strong>る</strong><strong>よ</strong>う<strong>に</strong>なったの<br />

でしょうか.<br />

直観主義 (intuitionism) <strong>と</strong>は⼤大まか<strong>に</strong>⾔言って, 数学<strong>に</strong>おけ<strong>る</strong>真<strong>理</strong>は⼈人<br />

間の思考<strong>と</strong>独⽴立したものではない, <strong>と</strong>いう⽴立場です.<br />

た<strong>と</strong>えば, ⼀一般的な (中学/⾼高校で習う) <strong>論</strong><strong>理</strong><strong>に</strong>おいては, すべての命<br />

題は証明可能かどうか<strong>に</strong>関わらず, 必ず真か偽<strong>に</strong>決定しています. ⾔言い換<br />

え<strong>る</strong><strong>と</strong>, 命題 P <strong>に</strong>ついて排中律が必ず成り⽴立ちます. ⼀一⽅方で, 既<strong>に</strong>⾒見てき<br />

た<strong>よ</strong>う<strong>に</strong>, 直観主義<strong>論</strong><strong>理</strong>は排中律を公<strong>理</strong><strong>と</strong>して認めません. 直観主義の⽴立<br />

場では,


での<strong>論</strong><strong>理</strong><strong>に</strong>おいては次の<strong>よ</strong>う<strong>に</strong>証明されます:<br />

1. 2は無<strong>理</strong>数であ<strong>る</strong>.<br />

2. 2 !<br />

を考え<strong>る</strong>. この<strong>と</strong>き, 2 !<br />

は有<strong>理</strong>数であ<strong>る</strong>か有<strong>理</strong>数でないかの<br />

どちらかであ<strong>る</strong>.<br />

a. 2 !<br />

が有<strong>理</strong>数<strong>と</strong>仮定す<strong>る</strong><strong>と</strong>, この命題は真. この<strong>と</strong>き


3. 数学は<strong>論</strong><strong>理</strong><strong>に</strong>先⾏行す<strong>る</strong>.<br />

これだけでは意味が取り<strong>に</strong>くいので, 少しかみ砕いてみましょう.<br />

1 は, 数学<strong>と</strong>は精神の「⾏行為」であ<strong>る</strong><strong>と</strong>いう主張です. 古典的な数学は,<br />

数や関数<strong>と</strong>いった抽象的な数学的対象を独⽴立して存在す<strong>る</strong>ものであ<strong>る</strong>か<br />

の<strong>よ</strong>う<strong>に</strong>扱ってきました. この⽴立場を実在<strong>論</strong> (realism) あ<strong>る</strong>いはプラト<br />

ニズム (Platonism) 2 <strong>と</strong>呼びます. ブラウワーは数学的対象や真<strong>理</strong>を, ⼈人<br />

間の精神<strong>と</strong>独⽴立して存在す<strong>る</strong>ものだ<strong>と</strong>は認めません. そのため, 数学の構<br />

成は⼈人間の精神的活動<strong>と</strong>してしか考えられません.<br />

1 のテーゼ<strong>よ</strong>り, 数学の発展<strong>と</strong>は, ⼈人間が時間の経過<strong>に</strong>従って数学の知<br />

識を得<strong>る</strong>こ<strong>と</strong>であり, 証明プロセスは時間軸<strong>に</strong>沿った数学の精神的な構成<br />

プロセス<strong>に</strong>ほかなりません. ゆえ<strong>に</strong>, 数学は時間を知覚す<strong>る</strong>こ<strong>と</strong>を前提<strong>と</strong><br />

します. 3 これが 2 の意味す<strong>る</strong><strong>と</strong>ころです.<br />

さて, 数学が⼈人間の直観<strong>に</strong><strong>よ</strong><strong>る</strong>ものでしかない以上, ⾔言語は数学をす<strong>る</strong><br />

上での道具<strong>に</strong>すぎません. ラッセルの<strong>論</strong><strong>理</strong>主義 (数学は<strong>論</strong><strong>理</strong>学<strong>に</strong>還元でき<br />

<strong>る</strong><strong>と</strong>す<strong>る</strong>⽴立場) や, ヒルベルト (David Hilbert, 1862-1943) の形式主義<br />

(数学の推<strong>論</strong>を純粋な記号の操作<strong>と</strong>して捉え<strong>る</strong>⽴立場) などは, ブラウワー<br />

<strong>に</strong><strong>と</strong>ってはナンセンスです. それらは⾔言語/記号やその操作<strong>と</strong>いった, い<br />

わば必然性を⽋欠いた数学の対応物<strong>に</strong>すぎないものを, 数学の本質や原<strong>理</strong><strong>と</strong><br />

して捉えてい<strong>る</strong>からです. 3 のテーゼはこの<strong>よ</strong>うな考え⽅方から帰結します.<br />

もちろん記号<strong>に</strong><strong>よ</strong><strong>る</strong>演繹の定式化がまったく意味をなさないわけでは<br />

ありませんが, しかしそれらは必ず, 直観主義的<strong>に</strong>妥当な⽅方法で⽤用いられ<br />

なければなりません. 例えば直観主義<strong>に</strong>おいて, 三段<strong>論</strong>法 (


ものでもなく, それだけで数学者の注⽬目を浴び<strong>る</strong><strong>よ</strong>うな主張ではありませ<br />

んでした. 4<br />

これらを公<strong>理</strong>化す<strong>る</strong>上で⼤大きな役割を果たしたのが, ハイティング<br />

(Arend Heyting, 1898-1980) <strong>と</strong>コルモゴロフ (A. N. Kolmogorov,<br />

1903-1987) です. コルモゴロフは命題<strong>論</strong><strong>理</strong>の, ハイティングは述語<strong>論</strong><br />

<strong>理</strong>の定式化をそれぞれ⾏行いました. ⼀一般的<strong>に</strong>, これらの定式化をブラウワ<br />

ー =ハイティング=コルモゴロフ解釈 (Brouwer-Heyting-Kolmogorov<br />

Interpretation), 略して BHK 解釈 (BHK Interpretation) <strong>と</strong>呼びます.<br />

BHK 解釈<strong>に</strong>おいて, <strong>論</strong><strong>理</strong>結合⼦子はそれぞれ次の<strong>よ</strong>う<strong>に</strong>解釈されます.<br />

1.


レーフ (Per Martin-Löf, 1942-) <strong>に</strong><strong>よ</strong>って考案された直観主義型<strong>理</strong><strong>論</strong><br />

(intuitionistic type theory, ITT) です. 直観主義型<strong>理</strong><strong>論</strong>は「依存型<br />

(dependent type)」の概念<strong>に</strong><strong>よ</strong>って⾼高階述語<strong>論</strong><strong>理</strong><strong>と</strong>計算を結びつけ<strong>る</strong>型シ<br />

ステムで, 定<strong>理</strong>証明器 Agda のベース<strong>に</strong>もなっています.<br />

カリー=ハワード同型対応<br />

ハイティング<strong>と</strong>コルモゴロフは, 命題<strong>と</strong>証明の間<strong>に</strong>次の<strong>よ</strong>うな関係があ<br />

<strong>る</strong>こ<strong>と</strong>をそれぞれ⽰示唆しました.<br />

命題 P 証明 p<br />

ハイティング P は意図 (志向) p は意図 P を充⾜足す<strong>る</strong>⽅方法<br />

コルモゴロフ P は問題 (タスク) p は問題 P を解決す<strong>る</strong>⽅方法<br />

ハイティングの捉え⽅方はブラウワーの観念<strong>論</strong>的な直観主義<strong>に</strong>忠実です.<br />

注⽬目すべきは, 後者のコルモゴロフの捉え⽅方です. ここでの「問題 (タス<br />

ク)」<strong>と</strong>その「解決」<strong>と</strong>いう語法は<strong>プログラミング</strong>を想起させないでしょう<br />

か?<br />

もう少し整<strong>理</strong>してみましょう. ここで登場す<strong>る</strong>のが型の概念です.<br />

例えば


ろ, 命題や<strong>論</strong><strong>理</strong>式<strong>と</strong>型の (propositions- or formulae-as-types), 証明<strong>と</strong><br />

プログラムの (proofs-as-programs) 間<strong>に</strong>あ<strong>る</strong>関係は単な<strong>る</strong>アナロジー<br />

ではなく, 形式的な対応<strong>と</strong>して成⽴立します.<br />

<strong>圏</strong><strong>論</strong><strong>と</strong>カリー=ハワード同型対応<br />

さて, 少し寄り道をしましたが, 驚くべきなのはここからです. なん<strong>と</strong>,<br />

カリー=ハワード同型対応は<strong>圏</strong><strong>論</strong><strong>に</strong><strong>よ</strong>り形式化できます.<br />

計算モデル <strong>論</strong><strong>理</strong> <strong>圏</strong><br />

型 A 命題 A 対象 A<br />

型 A から型 B を導出<br />

す<strong>る</strong>プログラム<br />

命題 A から命題 B を<br />

推<strong>論</strong>でき<strong>る</strong>こ<strong>と</strong>の証<br />

明<br />

射 f:A→B<br />

<strong>圏</strong>を⽤用いた<strong>論</strong><strong>理</strong>学を<strong>圏</strong><strong>論</strong><strong>理</strong> (categorical logic) <strong>と</strong>いい, <strong>論</strong><strong>理</strong>の<strong>圏</strong><strong>論</strong>的<br />

なモデルを⽤用いた意味<strong>論</strong>を<strong>圏</strong><strong>論</strong>的意味<strong>論</strong> (categorical semantics) <strong>と</strong>い<br />

います. また, あ<strong>る</strong><strong>圏</strong><strong>に</strong>対応す<strong>る</strong>計算モデルを 内部言語 (internal<br />

language) <strong>と</strong>いいます. これらの道具を使うこ<strong>と</strong>で, あ<strong>る</strong><strong>論</strong><strong>理</strong><strong>と</strong>計算モデ<br />

ルのカリー=ハワード同型対応を, <strong>圏</strong><strong>論</strong>の<strong>よ</strong>り抽象的な視点から考えられ<br />

<strong>る</strong><strong>よ</strong>う<strong>に</strong>なります.<br />

カリー=ハワード同型対応の結果<strong>と</strong>して, 単純型付きラムダ計算 (直<br />

積・直和・ユニット型・ボトム型があ<strong>る</strong>バージョン) <strong>と</strong>直観主義<strong>論</strong><strong>理</strong><strong>と</strong>双<br />

デカルト閉<strong>圏</strong>が対応しています. 以下, 直観主義<strong>論</strong><strong>理</strong><strong>と</strong>双デカルト閉<strong>圏</strong><strong>に</strong><br />

ついて紹介します.<br />

双デカルト閉<strong>圏</strong><br />

デカルト閉<strong>圏</strong> (Cartesian closed category) <strong>と</strong>は,<br />

1. 終対象を持つ<br />

2. 任意の 2 対象 A,B <strong>に</strong>ついて直積 A×B が存在す<strong>る</strong><br />

3. 任意の 2 対象 A,B <strong>に</strong>ついて冪対象 B A が存在す<strong>る</strong><br />

<strong>と</strong>いう 3 条件を満たす<strong>圏</strong>のこ<strong>と</strong>です.<br />

そして双デカルト閉<strong>圏</strong> (Bicartesian closed category) は, これら<strong>に</strong>加<br />

えて<br />

4. 始対象を持つ<br />

302


5. 任意の 2 対象 A,B <strong>に</strong>ついて直和 A+B が存在す<strong>る</strong><br />

<strong>と</strong>いう条件を満たす<strong>圏</strong>のこ<strong>と</strong>をいいます.<br />

具体的な対応<br />

ではい<strong>よ</strong>い<strong>よ</strong>, 型付きラムダ計算<strong>と</strong>直観主義<strong>論</strong><strong>理</strong>, お<strong>よ</strong>び双デカルト閉<br />

<strong>圏</strong><strong>に</strong>おけ<strong>る</strong>, 具体的な対応を⾒見ていきましょう.<br />

型付きラムダ計算の列<strong>に</strong>おけ<strong>る</strong>⻑⾧長い横棒は, 2 章で説明した「型付け可<br />

能性」のこ<strong>と</strong>であり, <strong>論</strong><strong>理</strong><strong>に</strong>おけ<strong>る</strong>シークエント計算<strong>に</strong>対応します.<br />

型付きラムダ計算 直観主義<strong>論</strong><strong>理</strong> 双デカルト閉<strong>圏</strong><br />

ユニット型 恒真式 T 終対象 1<br />

ボトム型 ⊥ ⽭矛盾 ⊥ 始対象 0<br />

Γ ⊢ :


Γ ⊢


+コントロール演算⼦子 +⼆二重否定除去規則<br />

線型型システム<br />

線型<strong>論</strong><strong>理</strong> (linear<br />

logic)<br />

スター⾃自⽴立<strong>圏</strong><br />

(*-autonomous<br />

category)<br />

単純型付きラムダ計算<br />

+依存型<br />

(dependent type)<br />

⼀一階直観主義述語<strong>論</strong><strong>理</strong><br />

(first-order<br />

intuitionistic<br />

predicate logic)<br />

⾼高階直観主義述語<strong>論</strong><strong>理</strong><br />

ハイパードクトリン<br />

(hyperdoctrine)<br />

Calculus of<br />

Constructions (CoC)<br />

(higher-order<br />

intuitionistic<br />

predicate logic)<br />

トポス (topos)<br />

計算<strong>と</strong><strong>論</strong><strong>理</strong>を⾒見事<strong>に</strong>抽象化す<strong>る</strong><strong>圏</strong><strong>論</strong><strong>と</strong>いう⾔言語の偉⼤大さがわかります<br />

ね. この<strong>よ</strong>う<strong>に</strong>, <strong>圏</strong><strong>論</strong>を軸<strong>と</strong>していろいろな世界を⾒見<strong>る</strong>こ<strong>と</strong>ができ<strong>る</strong>ので<br />

す.<br />

305


文献紹介<br />

ここでは, 記事を書く<strong>に</strong>あたって直接<strong>に</strong>参照した⽂文献<strong>に</strong>加え, 内容の<strong>よ</strong><br />

り深い<strong>理</strong>解<strong>に</strong>役⽴立つ資料をいくつか紹介します.<br />

第 1 章<br />

[1] ⼆二項関係 – Wikipedia (URL)<br />

[2] ラッセルのパラドックス – Wikipedia (URL)<br />

[3] カリーのパラドックス – Wikipedia (URL)<br />

[4] 公<strong>理</strong>的集合<strong>論</strong> – Wikipedia (URL)<br />

[5] クラス (集合<strong>論</strong>) – Wikipedia (URL)<br />

第 2 章<br />

[6] Morten Heine B. Sørensen, Paweł Urzyczyn『Lectures on the<br />

Curry-Howard Isomorphism』 (URL)<br />

執筆中は主<strong>に</strong> [6] を参考<strong>に</strong>しました. 型なしラムダ計算からカリー=<br />

ハワード同型対応<strong>に</strong>⾄至<strong>る</strong>まで, ⼀一から解説されています.<br />

この章ではほ<strong>と</strong>んど単純型付きラムダ計算<strong>に</strong>のみ触れましたが, 後述の<br />

[7] ではそれ<strong>に</strong>加え, System F や System Fω などの拡張も解説されて<br />

います.<br />

第 3 章<br />

[7] Benjamin C. Pierce 『Types and Programming Languages』 The MIT<br />

Press, 2002 年<br />

[8] Haskell/不動点<strong>と</strong>再帰 - Wikibook (URL)<br />

[7] は型<strong>理</strong><strong>論</strong>の教科書の定番<strong>と</strong>⾔言っても<strong>よ</strong>いでしょう. この記事の〆切<br />

直前<strong>に</strong>訳書の『型システム⼊入⾨門 ̶—<strong>プログラミング</strong>⾔言語<strong>と</strong>型の<strong>理</strong><strong>論</strong>̶—』(住<br />

井英⼆二郎 監訳, オーム社, 2013 年) が刊⾏行されました.<br />

[8] は不動点<strong>と</strong>再帰<strong>に</strong>ついての<strong>よ</strong>くま<strong>と</strong>まった解説です. Wikibook の<br />

Haskell の章 (URL) <strong>に</strong>は<strong>よ</strong>い記事が多いので, ぜひ英語版も含めて読ん<br />

でみてください.<br />

306


第 4 章<br />

[9] Saunders Mac Lane 著 三好博之/⾼高⽊木<strong>理</strong>訳『<strong>圏</strong><strong>論</strong>の基礎』丸善出版,<br />

2013 年<br />

[10] 清⽔水義夫『<strong>圏</strong><strong>論</strong><strong>に</strong><strong>よ</strong><strong>る</strong><strong>論</strong><strong>理</strong>学―⾼高階<strong>論</strong><strong>理</strong><strong>と</strong>トポス』東京⼤大学出版会,<br />

2007 年<br />

[11] 橋本光靖『<strong>圏</strong><strong>と</strong>関⼿手⼊入⾨門』(URL)<br />

[12] Diagonal Functor – Wikipedia (URL)<br />

現時点では⽇日本語の<strong>圏</strong><strong>論</strong>の⽂文献はわずかですが, ⼀一番ま<strong>と</strong>まってい<strong>る</strong>の<br />

は [11] です. [9] は定番の教科書で, <strong>圏</strong><strong>論</strong>の基礎から少し⾼高度なこ<strong>と</strong>ま<br />

で扱っており, この⼀一冊をちゃん<strong>と</strong>読めば<strong>圏</strong><strong>論</strong>の⼒力は相当つきます. [10]<br />

は少し異⾊色で, <strong>圏</strong><strong>論</strong><strong>と</strong><strong>論</strong><strong>理</strong>学を対照し, 「<strong>圏</strong><strong>論</strong>的普遍<strong>論</strong><strong>理</strong>」を提唱してい<br />

<strong>る</strong>本です. ⼊入⾨門書<strong>と</strong>してもかなり分かりやすい本ですし, <strong>圏</strong><strong>論</strong><strong>に</strong><strong>よ</strong><strong>る</strong>哲学<br />

<strong>に</strong>興味を持ってい<strong>る</strong>⼈人<strong>に</strong>も役⽴立つはずです.<br />

第 5 章<br />

[13] 萩野達也『A Categorical Programming Language』エディンバラ⼤大<br />

学博⼠士<strong>論</strong>⽂文, 1987 年 (URL)<br />

[14] 萩野達也『カテゴリー<strong>理</strong><strong>論</strong>的関数型<strong>プログラミング</strong>⾔言語』コンピュ<br />

ーターソフトウェア 7(1) pp.16-32, 1990 年 (URL)<br />

[15] ⽇日々の流転 2003 年 1 ⽉月 2 ⽇日 (URL)<br />

CPL の資料は少ないですが, CPL の発案者本⼈人が書いたものであ<strong>る</strong><br />

[13][14] は⾮非常<strong>に</strong>読みやすく⾯面⽩白いです. [14] <strong>に</strong>は CPL の基本アイデ<br />

ア<strong>に</strong>ついてかなり詳しく書いてあります.<br />

第 6 章<br />

[16] Varmo Vene 『 Categorical Programming with Inductive and<br />

Coinductive Types』タルトゥ⼤大学計算機科学科, 2000 年 (URL)<br />

[17] スペースアルク・語源辞典 (URL)<br />

この章を書く際<strong>に</strong>は [16] が<strong>と</strong>ても参考<strong>に</strong>なりました. 元の<strong>論</strong>⽂文が⾮非<br />

常<strong>に</strong>分かりやすく充実してい<strong>る</strong>ので⼀一度読むこ<strong>と</strong>をお勧めします.<br />

307


第 7 章<br />

[18] Eugenio Moggi『An Abstract View of Programming Languages』<br />

1989 年 (URL)<br />

[19] Haskell/<strong>圏</strong><strong>論</strong> – Wikibooks (URL)<br />

[20] 中村翔吾『モナドへの近道・Haskell からの寄り道』2007 年 (URL)<br />

第 8 章<br />

[21] ⼾戸次⼤大介『数<strong>理</strong><strong>論</strong><strong>理</strong>学』東京⼤大学出版会, 2012 年<br />

[22] 基礎演習 I <strong>論</strong><strong>理</strong>学 (URL)<br />

8 章の内容は基本的<strong>に</strong> [21] <strong>に</strong>準拠しました. この記事では⾶飛ばしがち<br />

<strong>に</strong>なってしまいましたが, ⼀一階述語<strong>論</strong><strong>理</strong>までの<strong>論</strong><strong>理</strong>体系が丁寧<strong>に</strong>解説され<br />

ています. 他<strong>に</strong>記号<strong>論</strong><strong>理</strong>学を⼀一から, かつ幅広く扱う⼊入⾨門書<strong>と</strong>しては『<strong>論</strong><br />

<strong>理</strong>学をつく<strong>る</strong>』(⼾戸⽥田⼭山和久, 名古屋⼤大学出版会, 2000 年) などがありま<br />

す.<br />

第 9 章<br />

[23] Per Martin-Löf『Intuitionistic Type Theory』1980 年 (URL)<br />

[24] ⾦金⼦子洋之『ダメット<strong>に</strong>たどりつくまで』勁草書房, 2006 年<br />

[25] ⽊木下佳樹『Agda ⾔言語<strong>に</strong>ついて』(URL)<br />

[26] 森⼝口草介『Cartesian Closed Category』スライド, 2011 年 (URL)<br />

[27] Till Mossakowski, Florian Rabe, Valeria De Paiva, Lutz Schröder,<br />

and Joseph Goguen『An Institutional View on Categorical Logic<br />

and the Curry-Howard-Tait-Isomorphism』(URL)<br />

ブラウワーの直観主義は実の<strong>と</strong>ころ, フレーゲ<strong>に</strong>始まり, ヒルベルトや<br />

ゲーデルなどを経て現在<strong>に</strong>⾄至<strong>る</strong>「数学の基礎づけ」<strong>と</strong>いう⼀一連の流れの中<br />

<strong>に</strong>位置づけられ<strong>る</strong>べきもので, 第 1 章で少し触れた「公<strong>理</strong>的集合<strong>論</strong>」など<br />

<strong>に</strong>も関係す<strong>る</strong>こ<strong>と</strong>がらです. これらの歴史的背景<strong>に</strong>ついては『ゲーデル 不<br />

完全性定<strong>理</strong>』 (訳・解説 林晋/⼋八杉満利⼦子, 岩波⽂文庫, 2006 年) <strong>に</strong><strong>よ</strong>い解<br />

説があります.<br />

308


記号一覧<br />

第1章 数学のおさらい


第2章 ラムダ計算<br />

Γ, … コンテキストの名前


第2章 ラムダ計算<br />

Γ, … コンテキストの名前


第2章 ラムダ計算<br />

Γ, … コンテキストの名前

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!