RustでFizzBuzz まとめ

Rust 0.1 (2012-01-26)
プログラミング言語 Rust - M59の記録
Rust 0.4 (2012-11-16)
Rust 0.4 - Ryusei’s Notes (a.k.a. M59のブログ)
Rust 0.7 (2013-07-06)
Rust 0.7 - Ryusei’s Notes (a.k.a. M59のブログ)
Rust 0.9 (2014-01-15)
Rust 0.9 - Ryusei’s Notes (a.k.a. M59のブログ)
Rust 0.10 (2014-04-04)
Rust 0.10でFizzBuzz - Ryusei’s Notes (a.k.a. M59のブログ)
Rust 0.13 dev (2014-12-16)
RustでFizzBuzz - Ryusei’s Notes (a.k.a. M59のブログ)
Rust 0.13 dev (2015-01-03)
RustでFizzBuzz - Ryusei’s Notes (a.k.a. M59のブログ)
Rust 1.6 Stable (2016-02-22)
Rust StableでFizzBuzz - Ryusei’s Notes (a.k.a. M59のブログ)

Rust StableでFizzBuzz

前回: RustでFizzBuzz - Ryusei’s Notes (a.k.a. M59のブログ)

安定版がリリースされてからは特段試してなかったことに気づいたので、今更ながら安定版で動くFizzBuzzを載せておく。

fn main() {
    use std::thread::spawn;
    use std::sync::mpsc::channel;
    use std::borrow::Cow;

    let n = 100;
    let (tx, rx) = channel();
    for i in 0 .. n {
        let tx = tx.clone();
        spawn(move || {
            let i = i + 1;
            let b = match (i % 3, i % 5) {
                (0, 0) => Cow::Borrowed("FizzBuzz"),
               	(0, _) => Cow::Borrowed("Fizz"),
                (_, 0) => Cow::Borrowed("Buzz"),
                _      => Cow::Owned(i.to_string())
            };
            tx.send((i, b)).unwrap();
        });
    }

    let mut res = Vec::new();
    for _ in 0 .. n {
        res.push(rx.recv().unwrap());
    }

    res.sort_by(|t, u| (&t.0).cmp(&u.0));
    for t in res.iter() {
        println!("{}", t.1);
    }
}

ハンコの意味論

ナンセンスなハンコ

先日、大学で進路説明会なるものが催され、某就活支援サービスの担当者が、就活の心得のようなものを語っていた。そこで、履歴書だかエントリーシートだかの書き方の話になったのだが、「綺麗に書いて最後にハンコを押す段階で失敗して書きなおすことになるのは時間の無駄であるしバカらしいから、先にハンコを押してから書くよう」と指南した。

書類を書く前にハンコを押すとは、ナンセンスに思える。そういうナンセンスな対処を得意げに語ることを許容する社会はどこか鈍いのではないか、誰かこのことをよく考えなければならないのではないかと、そう感じた。ハンコを押すならば、その行為にどのような意味があるか、考えるべきではないのか?

実際のところ、行為に意味があることと、その意味を行為者が認識している(意図がある)ことは別だ。記号は、それを取り扱う者(あるいは取り扱う物)がその意味を認識せずとも、意味を持っている。これは、記号の意味は人間の解釈から生まれるという旧来の記号観に反するが、一元論的記号論における記号観には合致している。一元論的記号論における記号は、時空間上でループをなす情報媒体の経路であり、人間の持つ高度な認知機能・言語機能を前提としない。とにかく、ハンコに意味があることと、ハンコを使う人がその意味を理解していることは別のことなのだが、「学ぶもの」を自認するなら、記号の意味は知っておきたいものだ。

ハンコの機能

それでは、ハンコを押すという行為にはどのような意味があるのか。契印・割印・消印・捨印・止印とは|知っておいて損はない!【はんこ豆事典】[1]には、「契印」「割印」「消印」「捨印」「止印」といった用途が解説されている。[1]に見出しとして出てはいないが、他に「署名捺印」「記名押印」「訂正印」という用途もある。

このうち「契印」「止印」「訂正印」は、文書の改竄を防ぎ、文書が当人によるものであることを保証する機能を持っているものであり、署名捺印(または記名押印)に使用した印鑑と同じ印鑑を使う必要がある。「署名捺印」「記名押印」は、書類が当人の手によるものであることの証であると同時に、書類中で使われる「契印」「止印」「訂正印」を有意味にしている。

「割印」は「契印」と似ているが、少し異なる。「契約書の正本と副本、原本と写しなどの二枚の書類が元々一枚だった証として両方にまたがって押印」[1]するのであるが、これは署名捺印(または記名押印)に使用した印鑑と同じ印である必要はない。これは、文書が当人によるものであることを保証するのではなく、書類間の相関性を保証するものだからだ。

訂正印の印影は、ハンコを持つ当人にとっては任意に押印が可能だが、他人には押印不可能だ。ハンコと書類はともに物理的実体を持ち、複製が困難である。ハンコと文書は偽造が困難で、書類上の印影がハンコの印影と一致するならば、それは必ずその当人が押したという証拠になる性質があるからこそ、そのハンコには意味がある。また、割印に至っては、全く同様の割印を押すことは何人にも不可能であり、そのことが意味を担保している。「割印」が意味を持つのは、「割印が一致する文書はもう一方の文書のみ」という複製不可能性を持っているからに他ならない。

これらの例が示すように、記号の意味は、記号が複製不可能(偽造困難)であることによって担保されるのであり、個々の情報経路(ハンコの印影)の複製可能性も、記号が必ず持つ性質というわけではない。

押印廃止

履歴書にハンコを押すことには、どのような意味があるのか。履歴書に印鑑の押印って必要?はんこはシャチハタでもいい? |【エン転職】[2]では、採用担当者に与える印象の観点から、印鑑を押印する必要性について論じている。[2]によれば、今の履歴書はそもそも押印欄がない場合がほとんどだという。その背景として、1997年に閣議決定された「申請負担軽減対策」に基づき定められた押印見直しガイドライン[3]が挙げられている。[3]は認印の押印について見直しを求めたもので、方針として(自署が義務づけられていない)記名と(自署が義務づけられている)署名に分け、見直しを進めるとしている。そこには、記名に押印を求めている場合は「押印を求める必要性や実質的意義が乏しく、押印を廃止しても支障のないものは廃止し、記名のみでよいこととする」とあり、その後に具体的に該当する例が列挙してある。また、署名に押印を求める場合は、「原則として押印を廃止し、署名のみでよいこととする」とある。

しかし、「必要性」「実質的意義」の詳細については、ガイドライン中に記述はない。このガイドラインを読んだ人間が、押印にどのような意義があるか理解していると(あるいは、その押印になぜ意義などないと言えるのか理解していると)期待できるだろうか。押印の意義を理解していない人間にも、押印の意義が理解できるようなガイドラインであるべきではなかったのか。押印の意義を理解できて初めて、不適切な押印が無意味であるということも分かるのではないだろうか。

署名がある場合に原則として押印を廃止するのは、署名それ自体に、その書類が当人の手によるものであると示す意味があるからだろう。しかし、先ほど見たように、署名捺印は他の意味も持っているから一概に署名捺印の捺印を廃止してよいとは言えない。訂正印を押す場合には、やはり捺印も必要になるだろう。(歴史的には署名→花押→印鑑と変遷してきた[4]のであり、筆記具の変化が大きいとはいえ、印鑑が廃止され再び署名に戻るというのは、奇妙だ。)

一方、記名に押印する場合は、記名だけでは押印と同じ意味を持たないから、押印を廃止するには「必要性」「実質的意義」の有無が問題とされるのだろう。履歴書は、「押印を求める必要性や実質的意義が乏しく、押印を廃止しても支障のない」例に「該当すると思われる」として列挙されたものに含まれている。履歴書は「単に事実・状況を把握することのみを目的としているもの」とされており、これに押印することは実質的意義などないと判断している。事実の確認をするだけだから、履歴書などは改竄される可能性が低いし、ハンコによる確認など必要ないということだろうか。事実の確認というのであれば、ハンコが押してあることが、その確認を意味あるものにするのではないだろうか?

しかし、よく考えると、そもそも今は認印の押印について話をしている。認印は印鑑登録されていないのだから、その認印が本人のものであるか確認する手段がないわけで、その時点で本人確認というハンコの意味は失われている。そのため、たとえハンコが押してあっても書類の正統性・完全性の保証にはならないし、改竄は防げない。

おわりに

ハンコには、書類の正統性・完全性の証明、書類の改竄の防止という機能が達成されるという、重要な意味があった。その意味を担保する手続きは煩雑になるだろうが、真に価値がある書類だからこそ、偽造されないように苦労し、工夫を施してきたわけだ。ハンコを廃止していいのなら、その書類は偽造されようが大した問題のない類の書類であり、その程度の価値の低い書類を人は書かされていたことになる。押印が廃止できるなら、書類自体廃止できるかもしれない。

結局のところ、「押印見直しガイドライン」というのは「実質的意義」などと言いながら、本当に押印の意味を議論することはなく、ただなんとなく無駄らしいという感覚で廃止しようというものだったのではないか。押印の意味を考えないから、「押印の廃止が、申請・届出の電子化・ペーパーレス化に資する点にも留意するものとする」などという意味の通らないことを言うのではないだろうか。電子化されようが、記号に求められる機能には変わりがない。電子化されてもなお、ハンコに相当する電子署名というものがある。電子署名もまた、無意味だから廃止とされるのだろうか。いや、既に形骸化し、意味が見失われた規則によって運用されている例はたくさんあるだろう。

この社会は、このように、不完全で、意味を持つかどうかよく分からない記号で溢れている。見方によって、それは形骸化したようにも、なお有意義なようにも見える。[1]は、履歴書に押印欄がある場合や、採用担当者から求められた場合には押印することとしている。印章ひとつで印象が変わる。書類の正統性を示す意味を失ってなお、就職に繋がるという意味があるのであれば、人はハンコを押すのだろう。ハンコは、誠実さを暗示する。ひとつひとつの記号は形骸化し、ほとんど意味がなくなろうとも、大量の誠実さの証があれば、その人間は誠実だと判断される。それもまた、記号の持つ力なのだ。

付録: 一元論的記号論の意義

ハンコの意味の分析を、旧来の記号論で行いうるだろうか、確認してみたい。(一元論的記号論は、未だアイディア段階だ。)

ここまで「意味がある」と表現してきたことは、むしろプラグマティクスで言う「効力」に近いのではないかと思うだろう。表現は対象と結びついている時に「効力」を持っていると考えられる。しかし、ハンコの意味というものは、表現と対象に分けることで理解できるものではない。割印は、片方の割印ともう片方の割印の対応性によって意味があるのであり、その関係は相対的である。ハンコと書類の関係も同じで、両方が物理的実体である。ハンコはまた、当人という存在に所有され、他人が物理的に手にすることはないという関係で結びついている。そして、割印が突き合わされ、ハンコの印影と書類の印影が照合され、そのハンコを当人が持っていることが知られていることで、記号の意味は確認される。

今の例は、記号の意味の確認がすべて人間の認識の中で起こっているのだけれども、記号を機械的に処理することもできるわけだから、人間が確認者である必要もない。人間が処理しようと機械が処理しようと、記号系全体の時空間におけるループの構造が同様であれば、つまり記号系が同じように振る舞えば、記号系全体は同じ意味を持つ。

一元論的記号論における「意味」の用法は、日常語としての「意味」によく合致し、説明できていると思う。これを、旧来の「シニフィアン」「シニフィエ」のような概念を使って分析するのは困難だ。(ハンコの意匠というシニフィアンに対応するシニフィエを探ったところで、ハンコの意味は出てこないだろう。)一方、「記号」の方は日常語としての用法からは離れている。ここで「記号」といった時、これは、旧来の記号の構成要素に相当する部分などを全部含めた、ループ状の情報経路全体を指している。一元論的記号論では「代表項」「心的対象」「外的対象」「シニフィアン」「シニフィエ」などといった概念は、「記号」(あるいは記号の束)の一部を恣意的に切り取ったものとして表現できる。

人間は、記号系自体を認識し、記号を見出すことができる。つまり、脳内に記号系のモデルを作り上げ、各部分間に相関性があると認識できる。「意味するもの」と「意味されるもの」という区別は、各部分自体の重要度によって決定されるのだろう。環状構造の絡みあった記号系の一部分だけを切り出して「意味するもの」と「意味されるもの」に分ける行為は恣意的な解釈で、これが旧来の意味での「記号」だと言える。書類の一部である印影を「意味するもの」とすると、「意味されるもの」は、印影を貫く記号*1の残りのどの部分のことでもよい。記号系の範囲を書類のワークフローに限定するか、社会全体とするかで、「意味されるもの」がどの範囲を指すかが変わってくる。

*1:印影を情報経路と見なしたとき、その経路を通る複数の記号すべて

一元論的記号論

記号論あるいは記号学と呼ばれる学問がある。これは、意味を担う媒体たる記号がなすシステム=記号系に普遍的な構造や性質を記述することによって、個々のシステムの分析に役立てることを目的としている。人間はあらゆる物事に意味を見出しうるので、記号論が対象とするシステムは世界全般にわたると言ってよい。あらゆるシステムに普遍的に存在する記号という概念を、どのようにモデル化するかが記号論の問題となる。

『記号と再帰』[1]では、既存の記号モデルを二元論と三元論に大別し、その両モデルがどのようにして統合されうるのかを、プログラミング言語を題材にして論じている。[1]の提示するモデルでは、記号は指示子・内容・使用という構成要素から成る。

しかしながら、既存の記号モデルは、二元論にしろ三元論にしろ、記号モデルとしては不完全だと私は考えている。なぜかというと、既存の記号モデルは心的対象としての記号を想定しているからだ。実際には、記号は物理的な世界と関係を持つし、記号を処理する存在もまた物的存在だ。すなわち、記号系として記述された系は、同時に物理系としても記述することができる。記号系としての記述と物理系としての記述の間には、何か対応関係があるはずだ。記号論も物理学もともに「普遍的な構造や性質を記述する」学問であり、心的対象と物的対象の区別が取り払われれば、両者は一致する。そこに、記号の物理的定義を考える必要性がある。

私の仮説では、「記号とは時空間上のループ」と考える。もう少し具体的に説明すると、時空間上の点Aから2物体p, qが出て、その未来の別の点Bで再び出会った時、p, q両者の経路を合わせると、時空間上のループになっている。(図1)同じ点Aから出ている2物体p, qは情報媒体であり、情報を共有していると考えられる。そういう情報を共有している媒体が異なる点Bで出会うという構造があるとき、つまり「時空間上のループ」が存在している時、その構造は記号と呼べるだろう。

f:id:mandel59:20160123032336p:plain 図1: 時空間上のループ状の軌跡

「記号とは時空間上のループ」というモデルによる一元論記号論は、系や媒体の規模を問わず、普遍的に適用できる。人間は介在しても、しなくてもよい。人間も人間以外の他の存在も等しく情報媒体として扱うからだ。例えば、点Aで地震が発生し、点Bである人が地震を経験する。そして、経路pを「発生した地震のP波を地震計が記録し、警報が発され、通信網を伝って人間に到達し、それを人間が認知し、その後実際に地震を経験する」経路、経路qを「発生した地震のS波が、地面を伝って人間に到達し、人間が地震を経験する」経路とする。警報の認知と地震の経験が人間の脳内で結びつき、警報が真に地震を知らせていた事実が確認される。

地震の情報が事前に伝わる」というためには、警報が伝わるだけでなく、警報が伝わった後に実際に地震を経験する必要がある。地震が来ないのであれば、警報は無意味となってしまう。情報が意味を持つか・持たないかということが、時空間上にループ構造ができているか・できていないかに対応している。

地震を経験した後に警報が鳴った場合も、その警報は無用ではある。しかし、その場合は「地震が警報の情報を伝えている」と言えてしまう。地震を経験することで、その後警報を認知するだろうということが予測できる。すなわち、地震と警報は、エネルギーの大小の差を捨象すれば、対称の関係だ。情報が伝わる段階では、「警報が地震を知らせている」のか「地震が警報を知らせている」のか、区別しようがない。「経路が情報を共有している」とは、つまり複数の経路が互いに別の経路の存在を知らせるという構造だ。既存の記号モデルは、このような対称性を説明しない。

地震が先に来た場合でも、人は普通、「警報が地震に間に合わなかった」と考え、「地震が警報を知らせている」とは考ない。しかしそれは単に、地震の方が警報よりも重大な現象だからだ。警報は人を脅かす程度だが、地震は実際に人間や財産に被害を及ぼしうる。そのような心理的価値判断が、現象のどちらを情報とし、どちらを情報の知らせる物事とするかを主観的に決めている。また、重大な現象に結びつく情報は価値ある情報だと言える。地震の前に来る警報は人間の適切な対処、ひいては人間や財産の保護に繋がるが、地震の後に来る警報は繋がらない。このような差異が、前者の価値を高め、後者の価値を低めている。

人間の主観的価値判断では無価値に思えた情報経路も、それが価値あるループの一部であることが判明すれば、経路に意味を見出せる。つまり、情報媒体の経路がループ構造を持つことを指摘することで、既存の記号論では取りこぼされてきた、主観的には無意味な記号の持つ隠れた意味を、客観的に提示できる。

有用な情報は価値ある情報で意味がある。無用な情報は価値なき情報で意味がない。記号の意味・価値・用法の本質は一体で、それは時空間上のループが存在することだ。記号の持つ恣意性は、経路の恣意性として説明できる。経路がどうあれ、ループ構造がトポロジカルに保存されるのであれば、経路は同じ役割を持ち、同じ価値を持ち、同じ意味である。記号の持つ多義性は、経路の共有性として説明できる。現実の世界は、大量のループが複雑に絡みあった形をしていて、それぞれのループが記号になる。経路が複数のループで共有されているならば、経路は複数の役割を持ち、複数の価値を持ち、複数の意味を持つ。

一元論記号論の記号モデルは、我ながら興味深いモデルだ。このモデルを使って今後実際の記号系の分析を行いつつ、一元論記号論を発展させたいと思う。

リファレンス

プログラミング言語は自然言語と本質から異なるのか

わたしは小説家になる以前、8年間ほどプログラマーとして働いていまして、こういう思考を始めると止まらないところがあります。コンピューター言語と小説の言語、自然言語は違うのか、という質問はよくされるのですが、これは本質的に異なります。プログラミング言語は人が機械を使役するためのものですから、すべてが命令形に則っています。

「~しろ」「~せよ」のみで、そこにコミュニケーションは存在しない。だから自然言語の対極の、さらに向こう側にあるとすら言っていいと思います。

だからコンピューターの言語が直接的に小説の言語に影響を及ぼすケースは考えにくいのですが、プログラマーとしての経験は、小説家としての自分に大いに役立っています。

http://wired.jp/2015/12/30/interview-yusuke-miyauchi/2/

命令もまたコミュニケーションの一形態であり、人間どうしのコミュニケーションとは大きく形態が異なるとはいえ、それが「本質的」差異だとはとても思えない。コンピューターというものが人間に使役される存在と見なされているにせよ、現に数多くのプログラミング言語には“対話型環境”が備えられてきたし、また、プログラムに誤りがあれば、機械は時に饒舌にそれを指摘してきた。人間どうしのコミュニケーションと形態こそ異なれども、そこにはある種のコミュニケーションが確かに存在していて、人間は機械と協働し、数多くのプログラムを作り上げている。

それに、プログラミング言語は命令形しか含まないという認識自体、正しくない。以前にも書いたが、〈プログラムとは命令文の並び〉という観点から行われるプログラミングは、数あるプログラミング観の一つに過ぎない。(プログラミングにおける〈式〉についての考察 - Ryusei’s Notes (a.k.a. M59のブログ))論理型言語や関数型言語の系統を遡れば、分析哲学的な概念記述の試みにたどり着く。それは人間の言語を形式化したものであり、人間の営みとしての思考や計算の様式を記述するものだった。その流れを汲んでいるプログラミング言語は、確かに人間の言語と繋がりを持っているはずだ。

私は、プログラミング言語自然言語を「本質的に差異のあるもの」として見るより「連続性を持ったもの」として見る言語観の方が好きだ。そして、その連続性を活用して、双方の言語の世界を広げ、あるいはコミュニケーションへの理解を深めていきたいと思っている。

〈式〉の考察 2

その1 ⇒ プログラミングにおける〈式〉についての考察 - Ryusei’s Notes (a.k.a. M59のブログ)

前回、式の望ましい性質として確定性・構成性・純粋性があるという話をした。これらの性質がなぜ望ましいのかを、実際に式を分析しながら詳しく見ていく。

式の構造

式は一般に、原子式と式の基本構造から再帰的に構成されている。

例えば、次の式1は、2つの式 ab,  c (a + b)と、式の基本構造 \square + \squareから成り立っている。そして、各部分式もまた部分と基本構造に分解できる。

式1:  a b + c (a + b)

式1の基本構造には次のものがある。

リスト1: 式1の基本構造

  •  \square \square
  •  \square + \square
  •  ( \square )

リスト1は、式を構成する規則として見ることができる。すなわち、これらの基本構造の組み合わせで、さまざまな式を構成できるわけで、どのようなものが式であるかを決めるルールになっているということだ。

式の構成規則を構文という。構文に従って式を分解し、式の構造を明らかにすることを構文解析という。

式1を構文解析していくと、式1を構成する次のような式が得られる。

リスト2: 式1の部分式

  •  a b + c (a + b)
  •  a b
  •  a
  •  b
  •  c (a + b)
  •  c
  •  (a + b)
  •  a + b

構文解析の途中で得られた、元の式を構成する式を、部分式という。今後、部分式と言った時には、元の式自体も含めることにする。

また、部分式のうち、基本構造を使って1回分解して得られた部分式のことを、ここでは「直下の式」と呼ぶことにする。式1の直下の式は ab,  c (a + b)の2つだ。

 a,  b,  cのように、構文によってこれ以上分解できない式を、原子式という。

構文木

式1を構文解析した結果は、次の図1のように木構造として表現できる。この木構造構文木と言う。

f:id:mandel59:20151129154749p:plain
図1: 式1の構文木

構文木の各ノードは、ある部分式と対応している。構文木の根は元の式と対応し、子ノードは直下の式と対応する。

曖昧な構文

式1は、 a b + c (a + b)という式と \square \squareという基本構造からなりたっているとみて、図2のように構文解析することもできる。

f:id:mandel59:20151129160323p:plain
図2: 式1の別の構文木

構文解析の結果が1通りでない式がある構文を、曖昧な構文という。構文が曖昧だと、構文解析の結果次第で、式の意味が変わってしまうというようなことが起きる。それでは困るので、普通は構文解析の結果が1通りになるような規則が設けられている。そのような規則に、例えば、演算子の優先順位がある。今後、ここで扱う式は、数学における数式と同じルールで構文解析するということにする。

式の値の計算

式の構成性は、次の性質だ。(前回の記述から修正してある。)

構成性 (compositionality): 式の値は、式の基本構造の機能と、直下の式の値のみから一意に決定される。

基本構造の機能とは、基本構造が表している〈足し算〉や〈掛け算〉のような計算のことだ。

式に構成性がある場合、すべての原子式の値が分かっていて、基本構造の機能をすべて実際に計算できると、次の手続き1に従って式の値が計算できる。

手続き1: 式Eの値を計算する

  • 手順1: 式Eの部分式のうち、まだ値が分かっていない部分式の中から、その式の直下の式すべてについて値が分かっているような式を、どれでもいいので、1つ選ぶ。その式をE’とする。
  • 手順2: 式E’の直下の式の値と、基本構造の機能から、式E’の値を計算する。
  • 手順3: 式Eの値が分かるまで、手順1, 2を繰り返す。

基本構造の機能が計算できるというのは、たとえば \square + \squareの部分の機能は〈足し算〉で、それを実際に計算できるということを表している。

実際に、上の手順で次の式2の計算をしてみよう。

式2:  2 \times 3 + 4 \times 5

式2の部分式は、式2自体を含めて次のものがある。(構文解析は数学と同じルールと決めたので、 3 + 4などは部分式でないことに留意してほしい。)

  •  2 \times 3 + 4 \times 5
  •  2 \times 3
  •  4 \times 5
  •  2
  •  3
  •  4
  •  5

そのうち、原子式 2,  3,  4,  5は値が最初から分かっている。

手順1: 式2の部分式の中で、直下の式すべてについて値が分かっている式は 2 \times 3 4 \times 5だ。ここでは 2 \times 3を選ぶとする。

手順2:  2 \times 3の直下の式の値 2,  3と基本構造の機能〈掛け算〉から、式の値を計算する。2と3を掛け算することで、 2 \times 3の値は 20だと分かる。

手順3: 同様に、 4 \times 5の値は 20だと分かる。すると 2 \times 3 + 4 \times 5の値も計算できて、6と20を足し算し、値は26だと分かる。

数式がどんなに複雑になっても、原理的には同じ方法で計算できる。もちろん、頭を使えばより効率的に計算することができる場合もあるが、とにかく機械的に式の値を計算することができる。

もし式に構成性がないと、手続き1は使えない。式の値が、直下の式の値と基本構造の機能だけから計算できないからだ。

プログラミングにおける〈式〉についての考察

「プログラムとは何か」という質問に対する、最も素朴な回答は「プログラムとは、機械に与える命令文の並びのことです」というものだ。命令文を解釈する機械が、プログラムに記された命令に従って、装置を制御し、計算処理を実行する。このようなことは、情報科学の基礎として学校で教えていると思う。

一方で、今日の高水準言語によるプログラミングでは、〈式〉という概念を理解していることがとても重要だ。特に、関数型プログラミングが注目されるようになった今日では、もはや単なる数式としての理解では十分でない。

しかし、プログラミング言語における〈式〉は〈サブルーチン〉や〈関数〉のような概念に比べると自明であるように思われているためか、あまり精緻な説明がなされないようだ。実際、Wikipediaにおける式 (プログラミング) - Wikipediaの記述の短さを見て欲しい。英語版であれば少しだけ記述が長いが、それでも十分な記述には程遠いものだろう。

プログラミングにおける〈式〉は、もっと語られてもいいはずだ。以下では、プログラミングにおける〈式〉の概念について、いくらか考察してみる。

プログラミング・パラダイムにおける式の観点の違い(概論)

以下、各プログラミング・パラダイムにおいて、式がどのような働きをしているかを考察する。各用語は、簡単な表現で説明できるように再定義しているため、巷での用法とは必ずしも一致しないことに注意を要する。「論理型プログラミング」や「関数型プログラミング」といった用語が、巷ではどのような意味で使われているかというのも興味深い話ではあるが、ここではその議論をしない。

命令型プログラミングにおける式

命令型プログラミングとは、〈プログラムとは命令文の並び〉という観点から行われるプログラミングのことだ。命令文を解釈する機械に命令を与えると、そのとおりに順次処理していくから、計算の仔細な手順(狭義のアルゴリズム)を、命令列によって与えれば、機械に計算を行わせることができる。

しかし、人間は大抵の場合、数学的な概念や計算を数式の形で記述ている。そのような数式を人間の手でアルゴリズムに変換するのは煩わしい。数式を与えると、その式の値を計算してくれる〈評価プログラム〉や、数式を与えると、その式の値を計算するための命令列を出力してくれる〈翻訳プログラム〉があると、楽で良い。〈プログラムとは命令文の並び〉という観点のプログラミング言語でも、高水準言語は当然のように〈数式〉を持っている。FORTRANの名の由来も「数式翻訳」“formula translation” だ。(FORTRAN - Wikipedia

命令型プログラミングにおける式は、ポピュラーな数学におけるような、計算して値を求めるための数式だろう。

論理型プログラミングにおける式

命令型プログラミングが〈プログラムとは命令文の並び〉という観点でプログラムするが、論理型プログラミングは〈プログラムとは平叙文の集まり〉という観点でプログラムする。平叙文というのは、「今年の平均気温は昨年より1度高かった」だとか「晴れている日に軒先に何か洗濯物を吊るしておくと、その洗濯物は乾く」のような、世界に関する事実や法則を表現する文だ。これを論理式の形で表現したものを、表明 (assertion) という。

命令型プログラミングによるプログラムの実行方法は、ただ「実行せよ」という命令であるのに対し、論理型プログラミングによるプログラムは、疑問文の形をとる。たとえば「月曜日の掃除当番は誰ですか」というような疑問を、自由変項 (free variable) という、「誰」や「何」に相当する分からない部分を指す項を含んだ論理式の形で与える。この論理式を、ゴール (goal) という。そうすると、マシンはプログラムされている事実や法則と、数理論理学に基づいた汎用の推論アルゴリズムを使って、ゴールが成り立つような例を見つけ出し、「月曜日の掃除当番は お父さん です」のように疑問に回答するわけだ。

事実と法則を与えておくだけで疑問に答えてくれる、ということが実現できるなら、それは人工知能と呼べるのだけれども、論理型プログラミングで推論がうまくいくのは、ごく限られている場合だけだ。きちんと問題が解けるようにするには、推論アルゴリズムの性質を理解し、適切な形で知識と法則を与えなければならない。だから、論理型プログラミングは、ごく基本的な使い方をする分には難しくないが、高度な使い方をしようとすると、途端に難しくなる。

論理型プログラミングにおける式は、自由変項を含んだ論理式であり、これを充足する解を求めるためのものだ。

関数型プログラミングにおける式

命令型プログラミング、論理型プログラミングを「プログラムとは○○」の形で簡潔に表現してきた。その流れで、関数型プログラミングは〈プログラムとは関数の集まり〉という観点でプログラムすることだと定義する。(繰り返しになるが、世間一般の用法とずれることを厭わず、こう定義している。)

関数は式を抽象したものだ。ここで言う抽象とは、式の可変部分を仮引数 (parameter) によって表すような操作を指す。具体例を挙げると、 10 \times 4 + 2という式があるときに、これを抽象し、f(x, y) = 10 \times x + yという関数を抜き出すことができる。

この関数を使えば、元の式は、関数に実引数 (argument) を指定した f(4, 2)という式で表現できるし、また f(7, 5)という式で 10 \times 7 + 5という式を表現できる。

関数型プログラミングによるプログラムの実行は、関数を含む式の値を計算することだ。ここまでの説明だけでは、関数で複雑なプログラムを書くことが出来るということが想像しがたい。しかし、実践的な関数型プログラミングにおいては、式の値としてポピュラーな数だけではなく、より複雑な構造を持った数学的オブジェクトを扱うので、とても実用的で汎用的なプログラミング・スタイルとなっている。

より一般的な〈式〉概念の説明

ここでは、式とは何かをより包括的に考えられるように、一般的に通用する定義を与え、プログラミング言語における〈式〉概念について考察する。

式 (expression) とは、プログラムのうち、値 (value) を持つ部分を指す。

式の望ましい性質には、次のものがある。(各項目の見出しは、例によってここでの議論における命名であって、一般的な用語とは必ずしも一致しない。)

  • 確定性 (definiteness): 式の値は一意に存在している。
  • 構成性 (compositionality): 式の値は式の構造と部分式の値のみから決定される。
  • 純粋性 (purity): 式は式の値以外の意味を持たない。

確定性があることによって、式の意味が明確に定まる。純粋性と構成性があることによって、部分式を、同じ値を持つ別の式と交換しても、式全体の値や意味が変化しないと言える。このような性質は、式に接している時に暗に了解している性質だ。

しかし、これらの性質を満たしていない式も多く存在している。例えば、 \frac{0}{0}という式の値は不定で、確定性がない。System.currentTimeMillis()という式は評価される時刻によって値が決まるから、構成性がない。System.out.println("Hello")という式は、値以外に〈標準出力へ文字列“Hello”を出力する〉という意味を持ってしまっていて、純粋性がない。

あるプログラミング言語の式が確定性・構成性・純粋性を持たないとしても、式の値の考え方を変えると、これらの性質を持つようになる場合がある。たとえば、「 \frac{0}{0}という式の値は不定」とせず、「 \frac{0}{0}は〈不定値〉という値を持つ」と考えることで、言語の本質的な仕様を変えずとも、式に確定性を持たせることができる。場合によっては、言語全体で式の値についての考え方を大きく変えなければならない場合もあるが、この方法は大抵実践可能だ。更に言えば、文のように元来値を持たないプログラムの構成要素に対しても、値を与えることで式にできる。

文のような、本来値を持っていない構成要素を式にできる、と言われても、抵抗があるだろうと思う。なぜ抵抗があるかというと、文の値を考え、文を式とした場合、言語の本質的な仕様を変えないという前提の下では、本来文だった式とそうでない式との間で、不公平な仕様が残る場合があるからだ。具体的には、もとの言語の仕様が「式の値は変数に代入できるが、文には値がないので代入できない」という仕様であったとすると、文に値を与えたところで、本質的な仕様の変更なしには、文は相変わらず変数に代入可能ではないままだからだ。しかし、「式の値は変数に代入可能であるべきだ」のような、個々の言語において望ましいとされている性質は、ここでは議論せず、まずは上記の3つの性質に絞って議論したいと思う。

つづく。

Everybody Loves Somebody

述語論理に限定継続を追加して、everybodyやsomebodyを表す項を作ってみる。

以下、{\bf C}, \langle \cdot \rangle はそれぞれ shift0, reset0 とする。

{\displaystyle
e = {\bf C}k. \forall x. k \hookleftarrow x \\
s = {\bf C}l. \exists y. l \hookleftarrow y
}

{\displaystyle
\langle L(e, a) \rangle \\
= \langle L( ({\bf C}k. \forall x. k \hookleftarrow x), a ) \rangle \\
\leadsto \forall x. \langle L( \square, a ) \rangle \hookleftarrow x \\
\leadsto \forall x. \langle L( x, a ) \rangle \\
\leadsto \forall x. L( x, a )
}

{\displaystyle
\langle L(a, s) \rangle \\
= \langle L( a, ({\bf C}l. \exists y. l \hookleftarrow y) ) \rangle \\
\leadsto \exists y. \langle L( a, \square ) \rangle \hookleftarrow y \\
\leadsto \exists y. \langle L( a, y ) \rangle \\
\leadsto \exists y. L( a, y )
}

同時に複数使うと、引数を右から評価するか左から評価するかで継続が異なるため、結果が一意にならず、英語の表現と同様に曖昧になる。

左から評価すると:
{\displaystyle
\langle L(e, s) \rangle \\
= \langle L( ({\bf C}k. \forall x. k \hookleftarrow x), ({\bf C}l. \exists y. l \hookleftarrow y) ) \rangle \\
\leadsto \forall x. \langle L( \square, ({\bf C}k. \exists y. k \hookleftarrow y) ) \rangle \hookleftarrow x \\
\leadsto \forall x. \langle L( x, ({\bf C}k. \exists y. k \hookleftarrow y) ) \rangle \\
\leadsto \forall x. \exists y. \langle L( x, \square ) \rangle \hookleftarrow y \\
\leadsto \forall x. \exists y. \langle L( x, y ) \rangle \\
\leadsto \forall x. \exists y. L( x, y )
}

右から評価すると:
{\displaystyle
\langle L(e, s) \rangle \\
= \langle L( ({\bf C}k. \forall x. k \hookleftarrow x), ({\bf C}l. \exists y. l \hookleftarrow y) ) \rangle \\
\leadsto \exists y. \langle L( ({\bf C}k. \forall x. k \hookleftarrow x), \square ) \rangle \hookleftarrow y \\
\leadsto \exists y. \langle L( ({\bf C}k. \forall x. k \hookleftarrow x), y ) \rangle \\
\leadsto \exists y. \forall x. \langle L( \square, y ) \rangle \hookleftarrow x \\
\leadsto \exists y. \forall x. \langle L( x, y ) \rangle \\
\leadsto \exists y. \forall x. L( x, y )
}

以下、Racketでの実装。

#lang racket
(require racket/control)

(define (forall x f) (if (null? x) #t (if (f (first x)) (forall (rest x) f) #f)))
(define (exists x f) (if (null? x) #f (if (f (first x)) #t (exists (rest x) f))))

(define (every x) (shift0 k (forall x k)))
(define (some x) (shift0 k (exists x k)))

(reset0 (even? (every '(10 20 30))))
(reset0 (even? (every '(10 20 5))))
(reset0 (even? (some '(5 7 9))))
(reset0 (even? (some '(5 7 10))))

0の0乗

はてなブックマークで、0の0乗についての記事がホットエントリーになっていた。

0の0乗の正解がネット検索しても見つからないので作成した。 | 子育ての達人 | 妊娠・出産・育児・子育ての毎日を楽しく

「いろんな言い分は多々見受けられましたが、正しい解答に言及しているサイト(ページ)は見つからなかった」というが、この記事自体に問題があると感じた。しかし、色々考えたけれども、あまりうまくまとめることができなかった。とりあえず、考えたことを以下にメモとして残しておく。

この記事では、一方で「なぜ2の0乗は1になる」と問うておきながら、マイナス乗については、「定義は定義としてすんなり受け入れなければいけません」と主張している。これはチグハグだ。

定義というのは、そこからの議論を厳密に行うために必要なものだ。数学で議論の対象になるもの(「数学的対象」という)は、無数に存在している。互いに似通った対象が多数存在するわけだから、数学では議論を始める前に定義を行い、どの言葉がどの対象を指しているかを決めておかなければならない。そうして、決めておいた定義や公理から推論して、様々な定理を導き出す。これが純粋に数学な議論だ。

「定義は定義としてすんなり受け入れなければいけません」という話は要するに「数学は定義が与えられて初めて議論が始められる」ということだ。マイナス乗をa^{-x} := \frac{1}{a^x}と定義するように、ゼロ乗もa^0 := 1 ~ (a \neq 0)などと定義して、数学的な議論を始めることができる。

しかし、件の記事の議論は違う。

累乗の説明が終わったので0乗の説明に行きます。ここまで来ると簡単です。

2^0=2^{1-1}=2^1 \times 2^{-1}=2/2=1

つまり、2の0乗というのは2/2(2÷2)なので1なのです。

例として2で進めましたが2以外の数でも同じです。従って、0の0乗とは、0/0(0÷0)のことです。

明らかに、これは定義から推論して法則を導き出す数学的な証明ではない。指数法則が成り立つように、a^0 := \frac{a}{a}と定義したいという、定義の動機の話だ。

「なぜ2の0乗は1になるか」「なぜ0の0乗は未定義になるか」という問いは、2通りに解釈できるということでもある。数学で「なぜPか」と言ったら、普通は「なぜPか、Pを証明して示せ」ということを意味している。しかし、2^0の定義がないうちには、「2^0 = 1を証明せよ」という純粋に数学的な問いは成り立たない。「なぜPか」という文のもう1つ、「なぜ数学者は(数学では)Pが成り立つような定義を採用するのか」を意味するだろう。これは数学者の動機の問題で、純粋に数学的な問題ではないし、コンセンサスも存在しない。

付録: なぜ私は2^0 = 1となるような定義を採用するのか

「定義の理由」にコンセンサスがあるわけではないけれども、「冪乗」と「指数関数」を使い分けて説明すると、理由を納得しやすいと思う。

掛け算の繰り返しで定義されている冪乗a^xには指数法則a^{x + y} = a^x \cdot a^yが成り立つ。一方で、別の方法で定義されている*1指数関数\exp_a xにも、指数法則\exp_a(x + y) = \exp_a{x} \cdot \exp_a{y}が成り立つ。xが正の整数であるときには指数関数と冪乗は一致し、\exp_a x = a^xとなる。だから、数学では多くの場合指数関数を冪乗と同じ記法で表しているし、同一視することもある。
この説明は、\exp_2 0 = 2^0 = 1となる理由を説明できるが、高校数学の範囲での指数関数は、底が0 < a \land a \neq 1の範囲でしか定義されていないから、0^x1^xの定義には、別の説明が必要になる。
考えが変わったので、取り消す。11月23日

定義の理由の理解がどのようであれ、定義自体が共有されているのであれば、数学的な議論を行う上で問題はない。

付録: 基数における冪の定義

濃度 (数学) - Wikipedia

集合Aの濃度を\#Aと書き、集合A, Bをそれぞれドメイン、コドメインとする写像の集合を{\rm Map}(A, B)と書く。基数 (cardinal number)  a, bの冪はa^b := \#{\rm Map}(b, a)と定義され、この定義の下では0^0 = \#{\rm Map}(\emptyset, \emptyset) = 1となる。

*1:指数関数の定義は同値の定義が複数存在している

RDFa Liteのここが酷い

RDFa LiteはRDFa Coreのサブセットで、とても短い仕様なのだけれども、一点気に入らない。

なぜ、@aboutではなく@resourceを採用したのか。

RDFa 1.1 Primerによれば、@aboutと@resourceの違いは、同じ要素に@propertyが設定されている場合の意味の差だけだ。どう違うかというと……

  • @aboutは、いつでも関係の主体 (subject) を設定する。
  • @resourceは、@propertyが設定されていない場合は@aboutと同様関係の主体を設定する。@propertyが設定されている場合は@hrefと同様関係の客体 (resource object) を設定する。(ただし、hrefと違って、クリックできないリンクになる。

属性名からも明らかなように、RDFa Coreの@resourceはリソースオブジェクトを設定するのが主用途だ。@propertyが設定されていない場合の意味は、「ついで」で決められていることに過ぎない。*1(これ自体センスがない仕様だ。意味が無い指定であれば未定義として残しておけばいいのであって、無理やり@aboutと同義にする必要がない。)

@resourceの唯一の意義であった「@hrefと違って、クリックできないリンクになる」という性質だって、今日のHTMLの仕様と組み合わせるのであれば、a要素の代わりにlink要素を使えば達成できるのだから、いよいよ@resourceの存在意義は無い。

@aboutを捨てて@resourceの方を選ぶというのは、全くセンスがない。他の属性が設定されているかどうかによって意味が変わる属性とか、ありえない。@propertyと@resourceを同じ要素に設定する“間違い”をしでかす人間は必ず出てくるし、仕様を策定する人間にセンスがないと、全世界に迷惑を掛ける。RDFa 1.1 Primerにその“間違い”を例示するぐらいだったら、最初から@aboutをプライマリとして採用してくださいよ。

*1:追記: subject、object両方とも、URIで指定されるのはresourceであり、resourceという名前がobjectを指しているという指摘は不当なので取り消す。しかし、場合によってsubjectの指定であったりobjectの指定であったりすることの筋の悪さに変わりはない。

schema.org/URLってダメ

Poor schema.org/URL - Ryusei’s Notes (a.k.a. M59のブログ)の雑な日本語訳。というか、原文が雑な英語すぎるし、まとまってない。)

schema.org/URL というデータ型が定義されているんだけど、これって酷いよね。「この属性のデータ型って何?」「URL。」って、答えになってないじゃん。

URLってのは、単なる識別子だよ。これはURLだなんて分かってる。ウェブにあるモノってのは、だいたいそれを指すURLを持ってる。知りたいのは、それがURLってことじゃなくて、そのURLが指しているモノの型が何なのかってことなんだから。

URLは、schema.org/Textのサブタイプであるべきじゃない。ハイパーリンクとして指定されているURLは、モノがある場所として解釈されるべきで、URLそれ自体がモノとして解釈されるべきではない。

Poor schema.org/URL

schema.org/URL is one of data types defined for linked data. I hate it, because it is totally useless. “Hey, what is the data type of this attribute?” “URL.” That is nonsense.

An URL is just an identifier. That is URL, I know. Almost every thing on the web have an URL that denotes it. What I want to know is the data type of the thing that the URL stands for.

URL should not the subtype of schema.org/Text. The URL specified for a property as hyperlink should be interpreted as the location that the thing is. Not be the URL itself the thing.

ソースコードは基本設計図か

www.nikkei.com

用語ミニ解説として、オープンソースが「基本設計図である「ソースコード」が公に開示されているソフト」と解説されているのだけれども、ソースコードは基本設計図なのだろうか。

基本設計図というのは建築における用語だ。建築では、設計図には基本設計図と実施設計図とがある。建築工事に必要なのは、実施設計図だ。www.homes.co.jp

建築における基本設計図とソフトウェアにおけるソースコードの間には、重大な差異がある。基本設計図の段階ではまだ建物は建てられないのに対して、ソースコードは既にビルドできる状態のもので、ビルドすれば実働するソフトウェアが得られるという点だ。建築にたとえるなら、ソースコードはすでに「建築工事」に回せる段階のものだから、これはむしろ「実施設計図」に相当する。