このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

人はどのように“記号の乱用”をしているのか

“記号の乱用”を実装すべきかもしれない」と「Catyに出現する名前達」において、名前が増えすぎて困る問題について述べました。困った状況は相変わらずです。

オーバーロードとか多相(総称、多態)は、名前を集約して減らす技術だとも言えるでしょう。実際、そのような技術を使わないと、名前はどんどん増えて、しかも長い名前となり、さらに悪いことには密接に関係する名前がまったく別な綴りを持ってしまうことがあります。

とりあえず、名前を減らす技術の使い方を云々する前に、ソフトウェアとは関係ない状況では「記号/名前の増加で困らない」のはなぜか? を考えてみます。

「記号/名前の増加で困らない」理由は、“記号の乱用”をするからです。僕は「“記号の乱用”を実装すべき」と思っているので、人間が行なっている典型的な乱用の仕方を調べてみよう、ということです。

内容:

  1. 人間のコミュニケーションの実際
  2. 名前の意味をもっと正確に
  3. どこから始めればよいのか
  4. 多ソートの構造

人間のコミュニケーションの実際

「Mはモノイドとする。」という数学的な言明を例にします。このような言い方は普通にされます。記号(名前)「M」の解釈には、次の3つのモノが必要です。

  1. とある集合。モノイドの台集合(underlying set)と呼ばれる。
  2. 台集合の特定の要素。モノイドの単位元(unit)と呼ばれる。
  3. 台集合のそれ自身との直積(対の集合)上で定義され、台集合に値を持つ写像。モノイドの乗法(multiplication)と呼ばれる。

「Mはモノイドとする。」と言ったとき、「台集合、単位、乗法を適当に想定してください。」という意味になります。各自が頭のなかで想定するだけなら、モノイドの各構成要素に名前なんて要らないのです。他に、単位元と乗法に関わる法則性がありますが、それも想定することになります。人間どうしのコミュニケーションは柔軟ですね。

「適当に想定してください」では困るときは、次のような言い方(書き方)が採用されることが多いでしょう。

  • M = (M, 1, ・) をモノイドとする。

ある程度慣れている人なら、これで話が通じます。次のように解釈するのです。

  1. イコールの左のMは、モノイド構造全体の名前とする。
  2. イコールの右に出現するMは、モノイドの台集合。モノイド構造全体と同じ名前だが、どちらの意味かは文脈により判断する。
  3. イコールの右に出現する1は、数値のイチとは限らず、モノイドMの単位元を意味する。
  4. イコールの右に出現する・は、モノイドMの乗法を意味する。(-・-):M×M→M という写像である(今出てきたMは台集合)。
  5. (M, 1, ・) は、モノイドとしての条件(公理)を満たす。

名前の意味をもっと正確に

人間は「これで話が通じる」のですが、ソフトウェアに対して話が通じるとはとうてい思えないので、もっと正確な記述をしてみます。

Mがモノイド構造全体の名前とした場合、(通常は意識されないにしろ)この名前に、台集合、単位元、乗法を対応させるメカニズムが背後にあるはずです。それを、U(-)、unit(-), mult(-) としましょう。ハイフンは無名変数で、ハイフンの場所にモノイドの名前が入るとします。

U(-)、unit(-), mult(-) を使うと、「M = (M, 1, ・) をモノイドとする。」は次のように書けます。

  • M = (U(M), unit(M), mult(M)) をモノイドとする。

これだと、モノイドの各構成要素には名前が必要なく、モノイド構造を表す名前Mから U(-)、unit(-), mult(-) で各構成要素が得られます。しかし、このような書き方が使われることは少なく、丁寧に書く場合でも、次のような書き方でしょう。

  • M = (|M|, 1M, ・M) をモノイドとする。

絶対値記号は台集合を表すためにたまに使われます*1。|M| は U(-) と同じことです。unit(M)の代わりに 1M、mult(M)の代わりに ・M です。この書き方は、実質的には U(-)、unit(-), mult(-) を使った場合と同じで、モノイド構造とその台集合、単位元、乗法を明確に分けて記述しています。

しかし、このような書き方がずっと使われ続けることはまずなくて、ほどなく次のような略記の約束がされます。

  1. 混乱の恐れがなければ、|M|をMと書くことにする。
  2. 混乱の恐れがなければ、1M を単に1と書く。
  3. 混乱の恐れがなければ、・Mを単に・と書く。

M, 1, ・ から |M|, 1M, ・M を再現するには、人間が持つ「文脈によるオーバーロード解決能力」に頼るわけです。我々が無意識に行なっている「文脈によるオーバーロード解決」は実に強力で、ソフトウェアに同等の能力を持たせるのは至難の業です。

どこから始めればよいのか

ソフトウェアが「文脈によるオーバーロード解決」を人間のように行うのはあまりにも大変なので、出来そうなことから始めましょう。モノイドのような構造と、その台集合を同じ名前で呼ぶ、というのはけっこうに重要なことだと思います。そして、比較的に実現は容易でしょう。

詳しく言うと:

  1. 構造の台集合を、構造と同じ名前で呼べる。
  2. 集合の名前により、その上に載っている構造を含めて指し示せる。

これはつまり、M = (M, 1, ・) という書き方を正式に許可することです。M = (M, 1, ・) と書いたとき、左の「M」は「M as monoid」で右の「M」は「M as set」です。同じ名前「M」に対して、as monoid か as set かを文脈で判断するのです。

1M と ・M は、M.unit、M.mult (あるいは unit<M>, mult<M>)のようにMを添えるにしても、M.unit ∈ M とか M.mult : M×M→M は解釈できるようになります。注意しないと分かりにくいですが、これらの表現のなかで名前「M]の多義的使用がされています。

  1. 「M.unit ∈ M」の、「M.unit」の「M」はモノイド構造
  2. 「M.unit ∈ M」の、「∈M」の「M」は集合
  3. 「M.mult : M×M→M」の、「M.mult」の「M」はモノイド構造
  4. 「M.mult : M×M→M」の、「M×M→M」の「M」は集合

整数のように、ひとつの集合にたくさんの構造が載っているときは問題があります。例えば、Intが整数を表すとして、

  1. 足し算に関するモノイドとしての整数
  2. 掛け算に関するモノイドとしての整数
  3. 足し算と掛け算に関する可換環としての整数
  4. 大小関係に関する線形順序構造としての整数

など、多くの構造があります。ですから、集合の名前「Int」から構造を一意に特定することはできません。主観的判断で典型的だと思う構造(例えば可換環)を「Int」と呼び、他は別の名前を付けるしかないでしょう。例えば、線形順序構造(linear order)としての整数は「IntLO」と呼ぶとか。

多ソートの構造

もう少し複雑な例もあります。「Vをベクトル空間とする。」という言明を考えてみましょう。ベクトル空間は足し算に関してモノイドで、足し算に対する逆元(反元)を持ちます。ですから、V = (V, 0, +, -) のように書けるでしょう。マイナスは反元を対応させる単項演算の記号だとします。(つまり、Vは可換群。)

さて、ベクトル空間は単なる可換群ではなくて、スカラー乗法を持ちます。これを記号「・」(さきほどと同じ記号を文脈によりオーバーロード)で表します。よって、V = (V, 0, +, -, ・)。ところが、スカラー乗法・の記述には、スカラー体(係数体)が必要です。結局、ベクトル空間Vの記述には、スカラー体Kの存在が必要なのです。

スカラー体Kも集合と演算から構成されますが、それらを列挙すると、K = (K, 0, +, -, 1, ・, ()-1) のように書けます。ベクトル空間Vに備わっているスカラー乗法・(スカラー体の掛け算と同じ記号をオーバーロードしてます)は、K×V→V のような写像です(スカラーが左から作用するとして)。これらを全部列挙するなら、次のように書くべきでしょう。

  • V = (V, K, ・)
  • V = (V, 0, +, -)
  • K = (K, 0, +, -, 1, ・, ()-1)

これでもだいぶ記号の乱用と略記をしていて、もう少し正確に書くなら、

  • V = (V0, K, ・V)
  • V0 = (|V0|, 0V0, +V0, -V0)
  • K = (|K|, 0K, +K, -K, 1K, ・K, ()-1K)

ベクトル空間の構造の名前「V」と(可換群としての)台集合は同じ名前で呼ぶことができるでしょうが、スカラー体を同じ「V」で呼ぶわけにはいきません。Vの構造の一部に「K」というスカラー体を示す名前を持つしかないのでしょう、たぶん。

集合と演算(写像)からなる構造といっても、ベクトル空間のように複数の集合から構成されることもあります。他ソート(multisort、many-sorted)な構造です。圏論的に言えば、インデックス付き圏またはファイブレーションが多段階の構成になることです。こういう状況でも名前を節約できる方法があるといいのですが、なかかなに難しいです。

こういうことを考えていると、人間とソフトウェアって随分と違うよなー、としみじみ痛感します。ソフトウェアを人間の感覚に合わせるには膨大な労力がかかりますね。

*1:絶対値記号は、圏Cの対象類Obj(C)を表すためにも使います。構造の台集合も圏の対象類も、一種の忘却関手とみなせます。