基本スキルの確認と練習 (G2 A6P3, C A7P3)

※ この練習問題は、前期、および今期の2つのセミナー(論理と圏論)に共通なので、一度やったことがあればやる必要はない。予備知識は特に要求しない。どの時点でやってもかまわないが、早めにやればそれだけ効果的。

ただし、この練習問題を全部やる必要はない。問題文を眺めて、「やったほうがいい」と判断したら選択的にやる。「分かった」と思ったらやめる。分かっていることを繰り返しやっても時間の無駄。

こ記事のテーマは、記号の取り扱いに十分に慣れること。我々は、様々な記号を操作し、その記号/操作の意味を考えなくてはならない。操作の対象物である記号を自由に操れる技量が必要になる。トレーニングしよう。

既に知っている/出来る問題はスキップしてよい。多くの人が知らない(であろう)事や、やったことがない(であろう)練習問題も含まれる。

※ 練習問題の解答は「解答: 基本スキルの確認と練習 (G2 A7R3, C A8R3)」にあります。

内容:

記法の多様性への対応能力のトレーニング

「書き方〈記法〉が変わると分からなくなってしまう」と感じる方は、次の“バカバカしくも手間がかかる練習”を、一度は愚直にやってみることをオススメする。ただし、「いくら何でももういいだろう」と思えばやめてよい。

記法の多様性への対応に問題がない方は、この手間のかかるトレーニングをあえてやる必要はない。

リスト(何かを並べたモノ)の書き方は多様である。書き方が変われば意味が変わる場合もあるが、意味が変わらないこともある。以下の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} である。列挙しない書き方(方向に無関係な書き方)の場合、動くインデックスを表す変数は適当に選んでよい。

  1. (a1, a2, a3, a4, a5)
  2. {X[i]}i∈{1,2,3}
  3. [A[1] | A[2] | A[3]]
  4. (δ(x) | x∈1..4)
  5. [k∈0..2 | Ψk + Θk]
  6. 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: 次の特殊配置方式(左右併置と右上付き)を含む式を、中置方式の演算子だけの式に書き換えよ。掛け算〈積 | 乗法〉の中置演算子記号は'×'、指数〈累乗 | ベキ〉の中置演算子記号は'^'〈ハット | サーカムフレックス | カレット | キャレット〉とする。

  1. ab
  2. aabbb
  3. a2b3
  4. a2x
  5. cba (TeXでレンダリングなら:  c^{b^a}
  6. x2y2 + 2xy
  7. ax2 + bx + c
  8. 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)
  • 弱: ◆

以下に関数呼び出し記法の式(等式もある)。

  1. foo(1, piyo(3))
  2. piyo(foo(hoge(a, b), baz(bar(s, t))))
  3. hoge(hoge(a, b), c)
  4. hoge(a, hoge(b, c))
  5. foo(foo(a, b), c)
  6. foo(a, foo(b, c))
  7. foo(foo(a, b), c) = foo(a, foo(b, c))
  8. piyo(piyo(x)) = piyo(x)
  9. bar(x, y) = -bar(y, x)
  10. piyo(baz(w)) = w

書字方向/描画方向の多様性への対応能力のトレーニング

圏論でも数理論理学でも、縦方向のテキスト・図が多用される。書字方向/描画方向の多様性に戸惑う人は多い。縦方向の書字・描画に慣れる必要がある。

どうしてこのようなトレーニングが必要なのかは、次の記事を参照。

書字方向/描画方向の多様性への対応に問題がない方は、このトレーニングをあえてやる必要はない。*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の掛け算)

と定義することもある。これは、異なる文脈での記号「×」のコンフリクトで、(頻繁に起きる)しょうがない事態だが、関数の直積を「\otimes」で表すこともある。つまり、

  • (f\otimesg)(a, c) := (f(a), g(c))

「×」を使うか「\otimes」を使うかは、コンフリクトを気にしないか/気にするかだけの違い、恣意的、好きにして。

集合 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 = ((+)\otimesid);(×);(/5)

次の図も参照。

x  y    z
---- +  -- id
 x+y    z
 --------- ×
  (x+y)×z
  ------------- /5
  ((x+y)×z)/5

(+), (+1), (3×) のような書き方をセクション記法という(プログラミング言語Haskellの書き方)。

問題 8: 次の関数定義を、中置演算子 +, × からのセクション記法を使ったポイントフリースタイルで書け。id(何もしない)、dup(複製する)、swap(入れ替える)関数は使ってよい。もちろん、結合〈直列結合〉記号 ; と直積〈並列結合〉記号 \otimes も使う。式は変形せずにそのまま、書き方を変えるだけ。

  1. f(x) = x2
  2. f(x) = x2 + 10
  3. f(x) = x2 + 5x + 10
  4. f(x, y) = 2x + 3y + 1
  5. f(x, y) = x2 + xy
  6. f(x, y, z) = z2 + (2x + 3y + 1)z

セクション記法は、中置二項演算子記号を関数名のように扱うためのものだが、前置単項演算子記号、後置単項演算子記号にも使ってみよう。

以下の式に登場する -(マイナス記号)は引き算ではなくて反数〈opposite〉を取る(符号を反転する)演算子だとする。後置の !(感嘆符)は階乗を意味する。

  • 3! = 3×2×1 = 6

単項演算子記号であるマイナス記号、感嘆符にもセクション記法が使えるとする。

  • (-)(5) = -5
  • (!)(3) = 3!

問題 9: 次の関数定義を、セクション記法を使ったポイントフリースタイルで書け。

  1. f(x) = (x + 1)!
  2. f(x) = (x + 1)! + x! + (x + -1)!
  3. f(x, y) = x! + -y
  4. f(x, y) = (x + -y)!
  5. f(x, y) = x!×y!
  6. f(x, y, z) = x!(y + -1)!(z + -2)!

[補足]
「ポイントフリー」はプログラミングで使われ始めた言葉。ここでの「ポイント」は集合の要素、「フリー」は「頼らない、使わない」の意味。つまり、「ポイントフリースタイル」は「集合の要素を使わない(書き方の)スタイル」となる。

圏論では、対象が集合のときでさえ、要素を使うのを避けるので、ポイントフリースタイルは圏論ととても相性がよい。要素を使わないということは、式や関数定義内で変数を使うことはできなくなる。変数は「なんらかの要素」を表すから。

したがって、ポイントフリースタイルでは、関数と関数の結合〈合成〉だけを使って式や関数定義を書く。結合以外に、関数の直積、関数のペアリングなどを使うこともある(今は詳しくは述べない)。
[/補足]

結合の記号を取り替える

記号の意味を強く固定せずに、柔軟に運用することが重要である。セクション記法を使ったポイントフリースタイル式では、もともと在った演算子記号は(セクション記法になって)残る。さらに、関数の結合〈直列結合〉の演算子記号 ; と直積〈並列結合〉の演算子記号 \otimes が含まれる式になる。例: ((+)\otimesid);(×);(/5)

もともとの演算子記号が ;, \otimes, \oplus のとき、これをセクション記法を使ったポイントフリースタイル式に直そうと思うと、演算子記号がかち合う*2。このような場合は、結合〈直列結合〉の演算子記号と直積〈並列結合〉の演算子記号を変更する。例えば:

  • 結合〈直列結合〉の演算子記号は *
  • 直積〈並列結合〉の演算子記号は \odot

問題 10: 上記の演算子記号 *, \odot を使って、次の関数定義をセクション記法を使ったポイントフリースタイルで書け。id, dup, swap は使ってよい。

  1. f(x) = (x\otimesx);x
  2. F(x, y) = a\otimesx \oplus b\otimesy
  3. ξ(f, g, h) = f;(g\otimesh) \oplus f;G
  4. g(x, y, z) = x;y;z \oplus z\otimesw
  5. Ω(a, b, f, g) = a;(f\oplusf)\otimes(g\oplusg);b
  6. k(α, β, γ, δ, ε) = α;((β\oplusβ)\otimes\oplusγ));(δ\otimesδ);ε

記号の選択は、まったく恣意的・無根拠に行われるものである。記号の意味を強く固定するがマズイのは、このような恣意的・無根拠な変更に対する反応が出来にくくなるからである。次のように記号の選択をしたとして、

  • 結合〈直列結合〉の演算子記号は |(縦棒)
  • 直積〈並列結合〉の演算子記号は &(アンド記号)

すぐ上の問題を再度やってみよ。つまり、

問題 11: 上記の演算子記号 |, & を使って、次の(上にある)関数定義をセクション記法を使ったポイントフリースタイルで書け。id, dup, swap は使ってよい。

くどいのだが、記号と意味の結び付きを柔軟に変更しながら対処する能力は、極めて重要なので、同様な練習をもうひとつ。

もともとの演算子記号が ;, \otimes, \oplus であるなら、通常の算術演算子 ×, + は使われてない。次のように約束する。

  • 結合〈直列結合〉の演算子記号は × (掛け算記号)
  • 直積〈並列結合〉の演算子記号は + (足し算記号)

問題 12: 上記の演算子記号 ×, + を使って、上にある関数定義をセクション記法を使ったポイントフリースタイルで書け。id, dup, swap は使ってよい。

使える記号の数が足りないので、既によく使われている記号を、意味を変えて流用する(オーバーロードする)事態は頻繁に起きる。既存の意味をサッと忘れて、新しい意味ですぐさま使えるようになる必要がある。

*1:この種の能力は、音感や運動能力などと同様に、ある程度は先天的な能力らしい。檜山は先天的能力が極めて乏しくて、小学校3,4年まで「右向け右」とか「お箸を持つほうに体を向ける」と言い換えてからでないと反応できなかった。そのため、書字方向、描画方向の脳内変換には今でも苦労する。もちろん、トレーニングは欠かせない。それが「双対や随伴に強くなるためのトレーニング」に書いた紙ナプキン・トレーニング。

*2:丸括弧で囲まれた記号と裸の記号で区別できる、のは事実だが、それで区別するのは辛すぎる。