※ この練習問題は、前期、および今期の2つのセミナー(論理と圏論)に共通なので、一度やったことがあればやる必要はない。予備知識は特に要求しない。どの時点でやってもかまわないが、早めにやればそれだけ効果的。
ただし、この練習問題を全部やる必要はない。問題文を眺めて、「やったほうがいい」と判断したら選択的にやる。「分かった」と思ったらやめる。分かっていることを繰り返しやっても時間の無駄。
こ記事のテーマは、記号の取り扱いに十分に慣れること。我々は、様々な記号を操作し、その記号/操作の意味を考えなくてはならない。操作の対象物である記号を自由に操れる技量が必要になる。トレーニングしよう。
既に知っている/出来る問題はスキップしてよい。多くの人が知らない(であろう)事や、やったことがない(であろう)練習問題も含まれる。
※ 練習問題の解答は「解答: 基本スキルの確認と練習 (G2 A7R3, C A8R3)」にあります。
内容:
- 記法の多様性への対応能力のトレーニング
- 演算子の書き方を変更する練習
- 書字方向/描画方向の多様性への対応能力のトレーニング
- 関数の直積、id, dup, swap
- セクション記法とポイントフリースタイル
- 結合の記号を取り替える
記法の多様性への対応能力のトレーニング
「書き方〈記法〉が変わると分からなくなってしまう」と感じる方は、次の“バカバカしくも手間がかかる練習”を、一度は愚直にやってみることをオススメする。ただし、「いくら何でももういいだろう」と思えばやめてよい。
記法の多様性への対応に問題がない方は、この手間のかかるトレーニングをあえてやる必要はない。
リスト(何かを並べたモノ)の書き方は多様である。書き方が変われば意味が変わる場合もあるが、意味が変わらないこともある。以下の72種の書き方は、違う意味で使われるかもしれないし、同じ意味で使われるかもしれない。
横方向に書く書き方 36種
- 囲み括弧 4種: 丸括弧〈小括弧〉, 角括弧〈大括弧〉, 波括弧〈中括弧〉, 括弧なし
- 区切り記号 3種: カンマ, 縦棒, なし(空白)
- インデックスの記法 3種: 下付き添字, 角括弧, 丸括弧
例: (x1, x2, ..., xn), {x[0], x[1], ... x[n-1]}, (x(1) x(2) ... x(n)), (x1 | x2 | ... | xn)
縦方向に書く書き方 9種
- 囲み括弧 3種: (縦長の)丸括弧, (縦長の)角括弧, 括弧なし
- 区切り記号 1種: なし
- インデックスの記法 3種: 下付き添字, 角括弧, 丸括弧
方向に無関係な書き方 27種
- 囲み括弧 3種: 丸括弧, 角括弧, 波括弧
- インデックスの記法 3種: 下付き添字, 角括弧, 丸括弧
- インデックスの範囲指定 3種: 縦棒の左側にインデックス集合, 縦棒の右側にインデックス集合, 右下に小さくインデックス集合
問題 1: 以下は、リストをあるひとつの書き方で書いたものである。同じ(あるいは対応すると思われる)リストを、残り71種の書き方で書け。n..m は 整数の区間で n..m := {k∈Z | n ≦ k ≦ m} である。列挙しない書き方(方向に無関係な書き方)の場合、動くインデックスを表す変数は適当に選んでよい。
- (a1, a2, a3, a4, a5)
- {X[i]}i∈{1,2,3}
- [A[1] | A[2] | A[3]]
- (δ(x) | x∈1..4)
- [k∈0..2 | Ψk + Θk]
- u1, u2, ..., un
演算子の書き方を変更する練習
これも、「書き方〈記法〉が変わると分からなくなってしまう」と感じる方のための練習。中置、前置、後置の演算子の使い方に慣れていれば、このトレーニングをあえてやる必要はない。
演算子/関数に、様々な書き方があるのは、習慣と視認性だけの理由。理論的にはすべて一緒。fが関数/演算子を表し、xとyがそれへの入力を表す。
- 中置方式
- 標準的な中置方式 xfy
- 左右下付き方式 xfy
- 前置方式
- 純ポーランド方式(区切り記号/囲み記号なし) fxy
- 標準的な関数呼び出し方式=タプル・ポーランド方式 f(x, y)
- 後置方式
- 純・逆ポーランド方式(区切り記号/囲み記号なし) xyf
- タプル逆ポーランド方式 (x, y)f
- 特殊配置方式 演算子記号を使わずに位置関係で示す
- 左右併置方式 xy
- 右上付き方式 xy
- 右下付き方式 xy
- 左上付き方式 xy
- 左下付き方式 xy
- 括弧方式
- 全体を囲む方式
- 単一引数を囲む (x)
- 複数引数を左右配置 (x, y)
- 複数引数を上下配置 書けない
- 片一方を囲む方式
- 右を囲む x(y)
- 左を囲む (x)y
- 全体を囲む方式
意味はすべて一緒、何の違いもない、書き方の違いに惑わされるな!
特殊配置 → 中置
問題 2: 次の特殊配置方式(左右併置と右上付き)を含む式を、中置方式の演算子だけの式に書き換えよ。掛け算〈積 | 乗法〉の中置演算子記号は'×'、指数〈累乗 | ベキ〉の中置演算子記号は'^'〈ハット | サーカムフレックス | カレット | キャレット〉とする。
- ab
- aabbb
- a2b3
- a2x
- cba (TeXでレンダリングなら: )
- x2y2 + 2xy
- ax2 + bx + c
- ex2 + y2
前置、後置
問題 3: 前問と同じ式を、純ポーランド記法に書き換えよ。次の表に従え。
中置二項演算子 | 前置演算子(の名前) |
+ | A |
× | M |
^ | E |
問題 4: 同様に、純・逆ポーランド記法に書き換えよ。
関数呼び出し
問題 5: 前々問と同じ式を、関数呼び出し方式〈タプル・ポーランド記法〉だけの式に書き換えよ。次の表に従え。
中置二項演算子 | 関数名 |
+ | sum |
× | prod |
^ | pow |
関数呼び出し → 色々
問題 6: 関数 foo, bar, baz, hoge, piyo の呼び出しを次の演算子を使った演算子記法に直せ。
- foo(x, y) = x◆y
- bar(x, y) = (x | y)
- baz(x) = x$
- hoge(x, y) = (x)y
- piyo(x) = 《x》
演算子の優先順位は:
- 強:《x》, x$
- 中: (x)y, (x | y)
- 弱: ◆
以下に関数呼び出し記法の式(等式もある)。
- foo(1, piyo(3))
- piyo(foo(hoge(a, b), baz(bar(s, t))))
- hoge(hoge(a, b), c)
- hoge(a, hoge(b, c))
- foo(foo(a, b), c)
- foo(a, foo(b, c))
- foo(foo(a, b), c) = foo(a, foo(b, c))
- piyo(piyo(x)) = piyo(x)
- bar(x, y) = -bar(y, x)
- piyo(baz(w)) = w
書字方向/描画方向の多様性への対応能力のトレーニング
圏論でも数理論理学でも、縦方向のテキスト・図が多用される。書字方向/描画方向の多様性に戸惑う人は多い。縦方向の書字・描画に慣れる必要がある。
どうしてこのようなトレーニングが必要なのかは、次の記事を参照。
- 双対や随伴に強くなるためのトレーニング
- 絵算(ストリング図)における池袋駅問題の真相
- 絵算の描画方向を示すために旗を使うことにした
- 記法バイアスと記法独立な把握: 順序随伴を例として
※ 序文〈リード文〉と、1, 2, 9節だけ読めばよい(中間は飛ばしてよい)。
書字方向/描画方向の多様性への対応に問題がない方は、このトレーニングをあえてやる必要はない。*1
次は連立不等式である。
x + y ≦ 7 x - y < 3
ひとつの不等式は左から右に書く。この方向を「不等式の方向」と呼ぶことにする。複数の不等式は上から下に並べる。この方向を「併置の方向」と呼ぶことにする。
不等式の方向(不等式を書く方向)を変えると:
方向→ x + y ≦ 7 方向← 7 ≧ y + x 方向↓ x + y ‖∧ 7 方向↑ 7 ∨‖ y + x
併置の方向(不等式を並べる方向)も同様に ↓, ↑, →, ← がある。不等式の方向と併置の方向の組み合わせの可能性は、→↓, →↑, ←↓, ←↑, ↓→, ↓←, ↑→, ↓← の8種がある。
問題 7: 最初の連立不等式をすべての方向(8種)で書け。また、以下の連立不等式も同様に、すべての方向で書け。
x + 3 ≦ 15 x ≧ 1 x + y < 3
x + y + z > 0 x2 + y2 + z2 ≦ 1 z ≧ 0
関数の直積、id, dup, swap
※ もとの記事(2018年)は、続きもの練習問題のひとつだったので、前の問題の知識を仮定していた。その前提知識をこの節で追加する。
A, B, C, D を集合、f:A→B, g:C→D を関数〈写像〉とする。関数fと関数gの直積 f×g:A×C→B×D を次のように定義する。
- (f×g)(a, c) := (f(a), g(c))
記号「×」を、数の掛け算と集合の直積でオーバーロードしていた事情から、例えば f:A→R, g:A→R に対して、
- (f×g)(a) := f(a)×g(a) (右辺の「×」はRの掛け算)
と定義することもある。これは、異なる文脈での記号「×」のコンフリクトで、(頻繁に起きる)しょうがない事態だが、関数の直積を「」で表すこともある。つまり、
- (fg)(a, c) := (f(a), g(c))
「×」を使うか「」を使うかは、コンフリクトを気にしないか/気にするかだけの違い、恣意的、好きにして。
集合 A, B に対して、id, dup, swap を次のように定義する。
- idA:A→A
idA(a) := a - dupA:A→A×A
dupA(a) := (a, a) - swapA:A×A→A×A
swapA(a, b) := (b, a)
下付き添字のAは省略することがある(当然に不正確になるが、書き方はたいていイイカゲン)。
セクション記法とポイントフリースタイル
中置演算子 + , × などに対して、対応する関数名を準備することがある。例えば:
- sum(x, y) = x + y
- prod(x, y) = x×y
しかし、新しい名前を決めるのがめんどうなので、記号 +, × をそのまま使い、
- (+)(x, y) = x + y
- (×)(x, y) = x×y
とすることがある。つまり、「中置演算子を丸括弧で囲むと関数名として前置で使える」というルールである。(+1), (3×) などは次の意味で使う。
- (+1)(x) = x + 1
- (3×)(x) = 3×x
このルールは、ポイントフリースタイル(下の補足参照)のときに威力を発揮する。f(x, y, z) = ((x + y)×z)/5 という関数をポイントフリーで書くと:
- f = ((+)id);(×);(/5)
次の図も参照。
x y z ---- + -- id x+y z --------- × (x+y)×z ------------- /5 ((x+y)×z)/5
(+), (+1), (3×) のような書き方をセクション記法という(プログラミング言語Haskellの書き方)。
問題 8: 次の関数定義を、中置演算子 +, × からのセクション記法を使ったポイントフリースタイルで書け。id(何もしない)、dup(複製する)、swap(入れ替える)関数は使ってよい。もちろん、結合〈直列結合〉記号 ; と直積〈並列結合〉記号 も使う。式は変形せずにそのまま、書き方を変えるだけ。
- f(x) = x2
- f(x) = x2 + 10
- f(x) = x2 + 5x + 10
- f(x, y) = 2x + 3y + 1
- f(x, y) = x2 + xy
- f(x, y, z) = z2 + (2x + 3y + 1)z
セクション記法は、中置二項演算子記号を関数名のように扱うためのものだが、前置単項演算子記号、後置単項演算子記号にも使ってみよう。
以下の式に登場する -(マイナス記号)は引き算ではなくて反数〈opposite〉を取る(符号を反転する)演算子だとする。後置の !(感嘆符)は階乗を意味する。
- 3! = 3×2×1 = 6
単項演算子記号であるマイナス記号、感嘆符にもセクション記法が使えるとする。
- (-)(5) = -5
- (!)(3) = 3!
問題 9: 次の関数定義を、セクション記法を使ったポイントフリースタイルで書け。
- f(x) = (x + 1)!
- f(x) = (x + 1)! + x! + (x + -1)!
- f(x, y) = x! + -y
- f(x, y) = (x + -y)!
- f(x, y) = x!×y!
- f(x, y, z) = x!(y + -1)!(z + -2)!
「ポイントフリー」はプログラミングで使われ始めた言葉。ここでの「ポイント」は集合の要素、「フリー」は「頼らない、使わない」の意味。つまり、「ポイントフリースタイル」は「集合の要素を使わない(書き方の)スタイル」となる。
圏論では、対象が集合のときでさえ、要素を使うのを避けるので、ポイントフリースタイルは圏論ととても相性がよい。要素を使わないということは、式や関数定義内で変数を使うことはできなくなる。変数は「なんらかの要素」を表すから。
したがって、ポイントフリースタイルでは、関数と関数の結合〈合成〉だけを使って式や関数定義を書く。結合以外に、関数の直積、関数のペアリングなどを使うこともある(今は詳しくは述べない)。
[/補足]
結合の記号を取り替える
記号の意味を強く固定せずに、柔軟に運用することが重要である。セクション記法を使ったポイントフリースタイル式では、もともと在った演算子記号は(セクション記法になって)残る。さらに、関数の結合〈直列結合〉の演算子記号 ; と直積〈並列結合〉の演算子記号 が含まれる式になる。例: ((+)id);(×);(/5)
もともとの演算子記号が ;, , のとき、これをセクション記法を使ったポイントフリースタイル式に直そうと思うと、演算子記号がかち合う*2。このような場合は、結合〈直列結合〉の演算子記号と直積〈並列結合〉の演算子記号を変更する。例えば:
- 結合〈直列結合〉の演算子記号は *
- 直積〈並列結合〉の演算子記号は
問題 10: 上記の演算子記号 *, を使って、次の関数定義をセクション記法を使ったポイントフリースタイルで書け。id, dup, swap は使ってよい。
- f(x) = (xx);x
- F(x, y) = ax by
- ξ(f, g, h) = f;(gh) f;G
- g(x, y, z) = x;y;z zw
- Ω(a, b, f, g) = a;(ff)(gg);b
- k(α, β, γ, δ, ε) = α;((ββ)(γγ));(δδ);ε
記号の選択は、まったく恣意的・無根拠に行われるものである。記号の意味を強く固定するがマズイのは、このような恣意的・無根拠な変更に対する反応が出来にくくなるからである。次のように記号の選択をしたとして、
- 結合〈直列結合〉の演算子記号は |(縦棒)
- 直積〈並列結合〉の演算子記号は &(アンド記号)
すぐ上の問題を再度やってみよ。つまり、
問題 11: 上記の演算子記号 |, & を使って、次の(上にある)関数定義をセクション記法を使ったポイントフリースタイルで書け。id, dup, swap は使ってよい。
くどいのだが、記号と意味の結び付きを柔軟に変更しながら対処する能力は、極めて重要なので、同様な練習をもうひとつ。
もともとの演算子記号が ;, , であるなら、通常の算術演算子 ×, + は使われてない。次のように約束する。
- 結合〈直列結合〉の演算子記号は × (掛け算記号)
- 直積〈並列結合〉の演算子記号は + (足し算記号)
問題 12: 上記の演算子記号 ×, + を使って、上にある関数定義をセクション記法を使ったポイントフリースタイルで書け。id, dup, swap は使ってよい。
使える記号の数が足りないので、既によく使われている記号を、意味を変えて流用する(オーバーロードする)事態は頻繁に起きる。既存の意味をサッと忘れて、新しい意味ですぐさま使えるようになる必要がある。
*1:この種の能力は、音感や運動能力などと同様に、ある程度は先天的な能力らしい。檜山は先天的能力が極めて乏しくて、小学校3,4年まで「右向け右」とか「お箸を持つほうに体を向ける」と言い換えてからでないと反応できなかった。そのため、書字方向、描画方向の脳内変換には今でも苦労する。もちろん、トレーニングは欠かせない。それが「双対や随伴に強くなるためのトレーニング」に書いた紙ナプキン・トレーニング。
*2:丸括弧で囲まれた記号と裸の記号で区別できる、のは事実だが、それで区別するのは辛すぎる。