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

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

コメント欄についてのコメントまとめ

Twitterのツイートをまとめました。

2012年


2014年1月17日

NATROMの日記のコメント欄が承認制になった時のコメントです。











2015年1月6日

Qiitaというウェブサイトのコメント欄が荒れた時のコメントです。

2015年7月28日

またQiitaのコメント欄が荒れていました。その時のコメントです。






2015年8月5日

コメント欄について議論する分野はどこなのかについての疑問です。



望ましいコメント欄の姿はなんだろう。

この記事は、イケダハヤト氏の記事に反応して書かれたものだ。コメント欄について、私は過去にもいくらか考えてきた。Twilogからコメント欄についてのコメントを拾い、あらためて自分の意見を確認した。

www.ikedahayato.com

この記事ではコメント欄を閉鎖する理由を「ゴミの掃き溜めです」、「建設的ではありません」と、説明している。一方で、「サイトコンテンツを拡充するという観点では、コメント欄は本来的には有意義」とも書いている。前者は、コメント欄につくコメントは無価値であると言っていて、しかし、後者はコメント欄が本来的に有価値であることを訴えている。

私もブログのコメント欄は閉鎖したほうがよい場合があると考えているが、それはコメント欄にゴミのようなコメントしか付かないから、議論が建設的でないから、といった理由ではない。だいたい「ゴミのような」だとか「建設的でない」のような判断は主観的な価値判断に過ぎないもので、ゴミのようなコメントが付いたり、建設的でない議論が繰り返されること自体から、何らかの意味を見出すこともできる。ゴミのようなコメントが付くコメント欄は十分有意義で、ただ記事の著者にとっては不都合・不愉快である場合があるというだけだ。

私が撤去したほうが良いと考えるコメント欄には、個々のコメントの管理の問題と、話題の管理の問題がある。

個々のコメント管理の問題というのは、社会的に問題のある発言を削除しなければならないということだ。もしコメント欄の管理を記事の著者自身で行っていると、コメント投稿者に、記事の著者にとって都合の悪い発言や反論が不当に削除・検閲されているのではないかという疑念を抱かせてしまう。最初から外部のサービスにコメント管理を委譲してしまい、著者自身で管理できないようにしてしまえば、著者は他人のコメントに何ら責任を負う必要がなく、とても気楽だ。

話題の管理の問題というのは、コメント欄が荒れることだ。はてなブログのコメント欄のように、コメントが一列のリストになっている場合、コメント欄の荒れが問題になりやすく、荒らしに脆弱だ。コメント欄が荒れて機能不全を起こすのは「記事に対するコメント」と「コメントに対するコメント」が区別されていないからで、スラドのようにツリー構造のコメント欄であれば、ツリーごとに異なる話題を続けられるから、ひとつの枝が荒れていても、他の枝に影響しづらい。あるいは、ツイッターのように、コメントどうしが勝手に参照しあうような構造でもよい。ツイッターのような構造は議論には向かなくなり、よりコメントらしい使い方になる。はてブのように、コメント量を制限しても、荒れることはない。

そういうわけで、撤去せずとも良いコメント欄は次の性質を持つ。

  • 著者自身が管理できない。個別のコメントの削除はコメントした人自身か、コメントサービス提供者が行う。記事の著者が他人のコメントに責任を負ってはいけない。
  • コメント欄の話題が1つにロックされない。複数の話題を持てるツリー型や、話題が存在しないツイート収集型、コメント量を制限するブックマークコメント型などにする。

Facebookコメント、Twitterの検索結果タイムライン、そしてこのブログにあるような、はてブコメント欄のどれも、この性質を満たしている。あとはコメント欄をブログに埋め込むかどうかは個々人の“衛生観念”の差で決まるもので、自分に対して批判的なコメントを読むのは精神に悪いからコメント欄を設置しないというのも、別にいいのではないかと思う。

CSSでヒラギノ角ゴシックのウェイトを指定する方法

※追記あります

Mac OS X El Capitanのヒラギノ角ゴシック — Medium

ヒラギノ角ゴシックは10ウェイトあるが、CSSでは9つ(100から900まで100間隔)でしか指定できない。しかも、具体的にどのウェイトで表示されるかが、ブラウザによって異なっているようだ。

f:id:mandel59:20151003203853p:plain:h411

font-weightと実際に使われるウェイトの対応の表:

CSS font-weight Firefox Chrome
100 W0 W0
200 W2 W1
300 W3 W3
400 W4 W4
500 W5 W5
600 W6 W6
700 W7 W7
800 W8 W8
900 W9 W9

また、normalとboldはそれぞれ400と700を指定するのと同じなのだが、今までのヒラギノ角ゴではW3とW6を使ってきたのだから、これでは少し太いかもしれない。こういう時は、@font-faceを使って、ウェイトと実際に使われるフォントの関係を直接指定してしまえばいい。

@font-face {
  font-family: "Hiragino Sans";
  src: local(HiraginoSans-W0);
  font-weight: 100;
}
@font-face {
  font-family: "Hiragino Sans";
  src: local(HiraginoSans-W1);
  font-weight: 200;
}
@font-face {
  font-family: "Hiragino Sans";
  src: local(HiraginoSans-W2);
  font-weight: 300;
}
@font-face {
  font-family: "Hiragino Sans";
  src: local(HiraginoSans-W3);
  font-weight: 400;
}
@font-face {
  font-family: "Hiragino Sans";
  src: local(HiraginoSans-W4);
  font-weight: 500;
}
@font-face {
  font-family: "Hiragino Sans";
  src: local(HiraginoSans-W5);
  font-weight: 600;
}
@font-face {
  font-family: "Hiragino Sans";
  src: local(HiraginoSans-W6);
  font-weight: 700;
}
@font-face {
  font-family: "Hiragino Sans";
  src: local(HiraginoSans-W7);
  font-weight: 800;
}
@font-face {
  font-family: "Hiragino Sans";
  src: local(HiraginoSans-W8);
  font-weight: 900;
}
@font-face {
  font-family: "Hiragino Sans W9";
  src: local(HiraginoSans-W9);
  font-weight: 900;
}
div {
  font-family: "Hiragino Sans";
  font-size: 20pt;
  line-height: 1.5em;
}
<div style="font-weight: 100">ヒラギノ角ゴシック W0</div>
<div style="font-weight: 200">ヒラギノ角ゴシック W1</div>
<div style="font-weight: 300">ヒラギノ角ゴシック W2</div>
<div style="font-weight: 400">ヒラギノ角ゴシック W3</div>
<div style="font-weight: 500">ヒラギノ角ゴシック W4</div>
<div style="font-weight: 600">ヒラギノ角ゴシック W5</div>
<div style="font-weight: 700">ヒラギノ角ゴシック W6</div>
<div style="font-weight: 800">ヒラギノ角ゴシック W7</div>
<div style="font-weight: 900">ヒラギノ角ゴシック W8</div>
<div style="font-family: 'Hiragino Sans W9'">ヒラギノ角ゴシック W9</div>

f:id:mandel59:20151003204830p:plain:h410

10月4日追記

上の方法だと、Firefoxでは正しく表示されるが、SafariGoogle Chromeだと、W5が正しく表示されない。
f:id:mandel59:20151004131621p:plain:h406 Safariでの表示
本来boldでないW5にfont-weight: 600を指定していると、機械的にboldになってしまうようだ。
やはりfont-weightを使わず、直接指定するのが無難だろう。

指定例: A Pen by Captain Anonymous

GMailのリプライをスレッドにまとめる機能は完全にダメ

GMailのアプリは関連するメールを一つにまとめる機能があるけど、この仕様を把握していないせいで完全に失敗した。メールに新規の未読のリプライが付いても、それは既読のメールの下に表示されるわけで、これじゃあ未読のリプライの内容を読み逃してしまうに決まっているじゃないか。なんでこんな仕様なんだ。

f:id:mandel59:20151001142047p:plain

https://support.google.com/mail/answer/5900?hl=ja

人力検索はてなの質問をキャンセルしたら内容が消えてしまったので、こちらに残しておく。

昔読んだ数学の児童書を探しています。 内容は断片的にしか覚えていません。おそらく12年以上前に図書館で読んだ本です。 小説仕立ての本であり、ワープロフロッピーディスクに、奇妙な外字で書かれた文書が保存されていて、それはコンピューターに住む未知の生命体の残した、未知の数学に関するメッセージだったというような話だったように思います。いくつかのトピックがあったと思いますが、そのひとつとして、p進数(p-adic number)に関連するようなトピックがありました。もしかしたら、大きめの判型の本で、上下で2冊分の本だったかもしれませんが、確かではありません。 少ない情報ですが、心当たりがあるかたはよろしくお願いします。

http://q.hatena.ne.jp/1443281726

www.amazon.co.jp

www.amazon.co.jp

ありがとうございました。

関数とラムダ計算の話

bugrammer.hateblo.jp

この記事へのツッコミみたいなことを書くつもりだったけど、あんまり関係ない話になったので、サイドストーリーみたいにして読んでください。

分野によって「関数」が違うこともある

前回、数学的な関数の定義の話があったけど、あれは写像の定義であって、個々の分野で「関数」と呼ばれているものと、いつでも一致するとは限らない。まあ普通は関数と言ったらほとんどの場合写像を指すので、少し違う物を指すときは、多価関数とか連続関数みたいに、別の名前を付けていることも多い。

で、プログラミングに関する文脈で「関数」と呼ばれるものが写像と一致するかといえば、もちろん一致しない。ある程度似た部分もあるけど、違う性質を持っている。この違いを、数学的にどうやって説明するかが問題になる。計算の性質を説明するための抽象モデルが抽象書換系で、ラムダ計算の意味も、抽象書換系によって定義できる。この定義の方法は、写像の定義とは大きく異なっている。

写像とラムダ項の間には、具体的にどういう違うがあるのだろうか。

一方で、写像には右一意性\forall a \in A, \forall b_1, b_2 \in B, ((a, b_1) \in G_f \wedge (a, b_2) \in G_f \Rightarrow b_1 = b_2)という性質があるが、ラムダ計算には合流性という性質があり、計算が停止する範囲では、写像とよく似た性質を持っているということが言える。

ラムダ計算の派生

ラムダ計算には、簡約の方法を制限したり、型を付けたりするといった、色々な派生系が存在していて、それぞれの体系が異なる性質を持っている。例えば、単純型付きラムダ計算は、型なしラムダ計算と異なり、計算が必ず停止する。(強停止性を持つ。)

よく知られている関数型言語の多くは、ラムダ計算から派生した体系を使っているが、ラムダ計算以外の体系を使った関数型言語も考えられる。

アクションと関数、式の値の話

bugrammer.hateblo.jp

  • a -> bというのは、引数にa型の値をとり、b型の値を返す関数の型だ。
  • Monad mが存在するような任意の型コンストラクタmについて、m aというのは、a型の値を生成する(Monad mの)アクションの型だ。

という型の意味を理解していれば、関数(>>) :: Monad m => m a -> m b -> m bは、その型から、

  • Monad mが存在するような任意の型コンストラクタmについて、
    • m a型の値(アクション)(これをxとする)を引数にとり、
    • m b -> m b型の値(関数)(これは(>>) xと表せる)を返す関数で、つまりその返される関数は、
      • m b型の値(アクション)(これをyとする)を引数にとり、
      • m b型の値(アクション)(これは(>>) x yと表せる)を返す関数で、つまりその返されるアクションは、
        • b型の値を生成するアクション

だということが読み取れる。

一方で、「m a型の値(アクション)xを破棄する」といったことは、型から読み取ることはできないし、事実でもない。実際、(>>) x y = (>>=) x (\z -> y)と定義でき、アクションxは破棄されない。破棄されるのはアクションxが生成する値で、それはxではなくzだ。

関数が値を返すということと、アクションが値を生成するということには大差がないように見える。実際に、多くのプログラミング言語は関数に副作用を認めていて、関数とアクションを区別しない。しかし、関数が、引数が定まれば返り値も一意に定まるという性質を持っているのに対し、アクションは、生成する値が定まるという性質を持っていないから、同列に扱おうとすると、式の値が一意に決まらなくなる、という困ったことが起きる。

そもそも、式の値はなんだろうか。(ここで書いている「手続き型プログラミング」「関数型プログラミング」という分け方は一面的なものに過ぎないから、あんまり深刻に考えないで欲しいのだけれども、)手続き型プログラミングにおいて、値というのは手続きから手続きへ渡されたり、変数に代入されたり読み出されたりするものであって、「式が値を持つ」という考えは、算術の式に対しては考えていても、プログラム一般に敷衍されるものではないように思われる。プログラムは文の集合だ。文は意味を持つが値を持たない。それが、手続き的なプログラミングにおいて一般的な考え方だ。

一方、関数型プログラミングでは、プログラムは式だ。関数型プログラミング言語の式は部分式と関数適用から構成されていて、どの部分式も値を持つ。関数型プログラミングでは、プログラムの構造を内包した値を扱うことでプログラミングするようになる。直和型の値は分岐構造を内包しているし、リスト型の値は反復構造を内包している。モナドは、手続き型言語における各種副作用を持つ、逐次構造を内包した型の集まり(型クラス)ということになる。このように複雑な値を使うことで、関数型プログラミングではプログラムの意味と式の値を同一視できるようになる。

プログラムの意味と式の値を同一視できると何が嬉しいかというと、意味を持つプログラムの断片がすべて値を持つので、プログラムを処理するプログラムが書きやすくなる。プログラムのどの断片も、関数として抽象化することができる。他の関数に渡すことが出来る。変数にプログラムを代入できる。

話をアクションに戻す。Haskellにおいては、アクションが生成する値と、アクション自体は別だ。たとえば、getChar :: IO Charは標準入力から文字を1文字読み込み、その文字に対応するChar型の値を生成するアクションなのだけれども、Haskellでは、式getCharの値は「標準入力から文字を1文字読み込み、その文字に対応するChar型の値を生成するアクション」自体であり、生成されたChar型の値ではない。アクションgetCharの生成する値を取り出して言及するには、do {z <- getChar; k z}zgetChar >>= \z -> k zzとでも言うしかない。

色々書いたけど、結局、値とは何かという話に合意が得られていない状況ではどうにも話が通じないという点が問題で、以前からココらへんの考え方を整理して参照透過性についてなんとか説明しようと試みたりしているのだけれども、やっぱり難しいですね。

追記のメモ書き

ツッコミどころ

  • Haskellにも値を持たない、式より上位の宣言の構造があるじゃん
  • プログラムの意味と値が一致しない純粋でない関数型言語なんてザラでしょ
  • 値を返す手続きを第一級の値として持てれば、純粋でなくても高度なプログラミングが簡単にできる上に、手続きを取り扱うだけのためにモナドを取り入れる必要がない。プログラムの意味と値を一致させる必要ってないんじゃないのか。
  • モナド以外に、一意型を使って値の複製を制限し、制御(ハンドラ)を表す値を導入することで、プログラムの意味と値の一致を図る方法がある。

ES6のジェネレータはHaskellのdo記法ほど強力ではないという話

curiosity-driven.org
postd.cc

この記事では、ES6のジェネレータを使って、Haskellのdo記法を模倣したdoM関数を定義し、ジェネレータを使ってモナドを取り扱えることを示している。しかし “The same routine can be used with other monads like the Continuation monad” という記述に反し、実はdoMと一緒に使えるモナドと、使えないモナドがある。

話を簡単にするため、以下ではECMAScriptのプロトタイプチェーン機能を使わないでプログラムを書くことにし、doMには、モナドを表現するオブジェクトを、引数として別途渡すことにする。

function doM(m, gen) {
  function step(x) {
    var y = gen.next(x);
    if (y.done) {
      return y.value;
    }
    return m.bind(y.value, step);
  }
  return step();
}

具体的に、ふたつのモナドOMGMを定義する。OMはOptionMonadの略で、GMはGeneratorMonadの略だ。

var OM = {
  unit: function(x) {
    return {tag: "Some", value: x};
  },
  bind: function(n, k) {
    if (n.tag === "None") {
      return {tag: "None"};
    }
    return k(n.value);
  },
};

var GM = {
  unit: function*(x) {
    yield x;
  },
  bind: function*(g, k) {
    for (var i of g) {
      yield* k(i);
    }
  },
};

このとき、OMに対してはdoMを適用できる。

var x = doM(OM, function*() {
  var a = yield OM.unit(2);
  var b = yield OM.unit(3);
  return OM.unit(a * b);
}());

console.log(x); // ==> Object { tag: "Some", value: 6 }

var y = doM(OM, function*() {
  var a = yield OM.unit(2);
  var b = yield {tag: "None"};
  return OM.unit(a * b);
}());

console.log(y); // ==> Object { tag: "None" }

一方で、GMに対してdoMを使うと、例外が出てしまう。

var z = doM(GM, function*() {
  var a = yield function*(){ yield 2; yield 3; yield 4; }();
  var b = yield function*(){ yield 5; yield 6; }();
  return GeneratorMonad.unit(a * b);
}());

try {
  for(var i of z) {
   console.log(i);
  }
} catch (e) {
  console.log(e); // ==> TypeError: k(...) is undefined
}

なぜかといえば、GM.bindは第2引数k複数回呼び出す可能性があるからで、一方、doM内で定義されている関数stepは、ジェネレータの呼出しに副作用を使うことを前提としていて、複数回呼び出されることを考慮しない作りになっているという点が問題となっている。この問題を修正するには、途中まで実行したジェネレータを複製することができる必要があるが、ES6のジェネレータにそのような機能はないようなので、結局ジェネレータを使ってどのようなモナドにも対応したdoMを実装することはできないということになる。

比較用に、doMを使わない場合のコードも載せておく。

var w = GM.bind(function*(){ yield 2; yield 3; yield 4; }(), a =>
        GM.bind(function*(){ yield 5; yield 6; }(), b =>
        GM.unit(a * b)));

for(var i of w) {
  console.log(i);
}

「抽象化」を抽象化する 〜 nopは確かに抽象化のひとつの形であるという話のメモ書き

さて、以上の議論を踏まえた上で、「世界一抽象化されたコード」というのを今から書いてみましょう。一瞬でかけます。

# nop

上にあげたものがそうです。つまり、「なにもしない」というコードこそが、世界一抽象化されたコードです。

http://nekogata.hatenablog.com/entry/2015/08/05/001742

これが本当に抽象なのか? と疑問に思う人がいるのだけれども、これは確かに一種の抽象化ではあるのだ。これが抽象化だと思えないのは、このnopの例自体が、具体的にどういう抽象化を前提としているかを明示していない、抽象的な例だからだ。「抽象化」という概念それ自体が抽象的だ。関数は、機械に扱える抽象化の機構のひとつなのだけれども、だからといって関数だけが抽象化ではない。

抽象化というのは、プログラムを書くのに使える概念であるという以前に、物の考え方としての概念だという側面がある。このnopの例は、少なくとも、もはやRubyが形式化しているレベルの抽象を越えてしまっていて、それは計算機にとっては意味を持たない(具体的に計算できない)抽象化だ。Ruby処理系に# nopというコード自体を渡しても、これはコメントを含む空のプログラムだと具体的に解釈されるだけであって、全く抽象性を持たない。だけど、そういう、機械にとって意味を持たない抽象化でも、人間にとっては意味のある何かを抽象している場合がある。コメント行自体もそうだし、アルゴリズムの本などが載せている擬似コードなどは、機械が読めずとも人間が読める、抽象的なコードだ。その抽象的なコードは、人間が適宜解釈し、具体的なプログラミング言語で実装することができる。

条件分岐if C then A else Bを抽象化して、非決定性の分岐A ⊕ Bとして考える、といった話と似ている。(抽象化というより、近似と言ったほうがいいのかもしれないけど。あるいは、抽象化というのは、別の視点を変えれば、近似と見ることができる。)

普通プログラマが抽象化と言ったら、機械が扱える範囲での抽象化だけ考えているんだ、と言うかもしれないけど、どういう種類の抽象化を機械が扱えるかというのは、曖昧だ。擬似コードだって、十分に形式化されていれば、処理系を実装して実行することができる。

まとまらないけど、メモ書きだからこれで終わり。

CoffeeScriptで代数的データを表現する

関数型言語ではポピュラーな機能である、代数的データ型を愛してやまない人は多いだろう。しかし悲しいことに、CoffeeScriptは、代数的データ型を持っていない。今回は、オブジェクトを使って代数的データの条件分岐を表現する方法について書こうと思う。

次のコードは、数式の文字列化や評価を行うプログラムだ。

# 分岐関数
match = (x, c) -> x.apply(c)

# 構築子
num = (x) -> ->@num(x)
add = (x, y) -> ->@add(x, y)
mul = (x, y) -> ->@mul(x, y)

# 数式 1 + 2 * 3
exp = add(num(1), mul(num(2), num(3)))

# 文字列化
p = (exp) -> match exp,
  num: (x) -> String(x)
  add: (x, y) -> "(" + p(x) + ")+(" + p(y) + ")"
  mul: (x, y) -> "(" + p(x) + ")*(" + p(y) + ")"

# 評価
ev = (exp) -> match exp,
  num: (x) -> x
  add: (x, y) -> ev(x) + ev(y)
  mul: (x, y) -> ev(x) * ev(y)

console.log p(exp) + " = " + String(ev(exp))

実行すると、次のように表示される。

(1)+((2)*(3)) = 7

構築子

構築子は、次の形をしている。

c = (x...) -> ->@c(x...)

(仮引数列) -> 式は関数を作る構文、-> 式は引数のない関数をつくる構文で、@メソッド名(実引数列)JavaScriptthisメソッドを呼び出す。つまり構築子cは、this.cx...を引数として呼ぶクロージャーを返す関数だ。

分岐関数

条件分岐は関数matchに、代数的データと、分岐ごとの処理を表すオブジェクトを渡して行う。

分岐関数内では、渡された代数的データ(実体はクロージャー)をオブジェクトに適用している。

match = (x, c) -> x.apply(c)

こうすると、クロージャーがオブジェクトの適切なメソッドを呼び出し、条件分岐を行ってくれる。

もうひとつの方法

別の方法として、次のような分岐関数と構築子を使う方法が考えられる。

# 分岐関数
match = (x, c) -> c[x[0]].apply(c, x[1..])

# 数式の構築子
num = (x) -> ["num", x]
add = (x, y) -> ["add", x, y]
mul = (x, y) -> ["mul", x, y]

Debug the Haxe Compiler with OCamlDebug

1. Apply the following patch to the Makefile:

diff --git a/Makefile b/Makefile
index e912e15..1f6c71f 100644
--- a/Makefile
+++ b/Makefile
@@ -80,7 +80,7 @@ libs:
        make -C libs/objsize OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
 
 haxe: $(MODULES:=.$(MODULE_EXT))
-       $(COMPILER) -o $(OUTPUT) $(NATIVE_LIBS) $(NATIVE_LIB_FLAG) $(LFLAGS) $(LIBS:=.$(LIB_EXT)) $(MODULES:=.$(MODULE_EXT))
+       $(COMPILER) -g -o $(OUTPUT) $(NATIVE_LIBS) $(NATIVE_LIB_FLAG) $(LFLAGS) $(LIBS:=.$(LIB_EXT)) $(MODULES:=.$(MODULE_EXT))
 
 haxelib:
        (cd $(CURDIR)/extra/haxelib_src && $(CURDIR)/$(OUTPUT) haxelib.hxml && nekotools boot bin/haxelib.n)

2. Build the compiler with the following command:

make BYTECODE=1

3. Execute ocamldebug:

ocamldebug ./haxe [arguments]
% ocamldebug ./haxe
	OCaml Debugger version 4.02.1

(ocd) break @ Main 979
Loading program... done.
Breakpoint 1 at 3223236: file main.ml, line 980, characters 2-29726
(ocd) run
Time: 69442 - pc: 3223236 - module Main
Breakpoint: 1
980 	<|b|>let usage = Printf.sprintf
(ocd) n 20
Time: 69757 - pc: 3223608 - module Main
1000 	Common.define_value com Define.HaxeVer (float_repres (float_of_int version /. 1000.))<|a|>;
(ocd) p version
version: int = 3300
(ocd) rev
Time: 69442 - pc: 3223236 - module Main
Breakpoint: 1
980 	<|b|>let usage = Printf.sprintf
(ocd) prev
Time: 69441 - pc: 3198700 - module Main
637 			<|b|>init ctx;
(ocd)

You can even trace back to the past!

Check the debugger commands at The debugger (ocamldebug).

Happy hacking!

哲学無用論と哲学の価値

哲学は役に立たないのではないか、という批判はソクラテスのむかしからあるようだ。(理想国のあり方と哲学の役割──『国家』第5-7巻)そういう哲学無用論に反論する方法のひとつに、哲学の有用性を具体的に説くというものがある。

logmi.jp

でも、哲学が役に立った例を具体的にいくら挙げたところで、“本質的に”哲学の有用性が示されたことにはならない。どれも、特定の哲学の考えが有用であったというだけで、相変わらず、何の役に立つのか分からない哲学もある。すべての哲学に、その用途をあてがうのは不可能だろう。

有用な諸科学も、源流を辿れば哲学に由来しているのだから、今の哲学もいずれ有用となるはずだとも考えられる。ソクラテス「星を見つめる男」の比喩にしたって、天文学という一見無用に見える学問が航海術に役立つということに喩えている。アインシュタイン一般相対性理論全地球測位システムGPS)の構築に不可欠なのだから、理論物理学は有用であるという話と変わらない。しかし、このような考え方は、楽観的だ。

哲学も役に立っているという論で救われるのは役に立つことが明らかになっている哲学だけだし、将来役に立つという説明では、悲観的なひとを納得させられないだろう。哲学を、有用性の観点から価値付けようとする試みは、そもそも無理があると思う。ある種の哲学は実際に無用で、その前提は覆らない。

それでも、哲学には価値がある。その価値とは、希哲学 philosophy という名が示している通りの価値だ。哲学に価値をもたらしているのは、知ることへの強烈な欲求だ。人間は、食欲や睡眠欲と並んで、知ることに対して抗いがたい欲求を持っている。食事は諸活動に必要だが、同時に食事自体が楽しみだ。食事に興味を持たず、完全に単なる手段とみなし、実用性・合理性を追求する人間は、極少数派だろう。(もしいるとしたら、そいつはたぶん哲学者だ。食事する哲学者の問題 - Wikipediaそれかサンドウィッチ伯爵か。結局、どの欲求が一番強いのか、という話だ。)

肉を食らうことも本を食らうことも等しく人間的で、健康に関係し、価値のあることだけれども、役にも立たない本を食らうことに何よりも強い満足感を感じる人間というのは、やはり少数派なのだろう。

「哲学は役に立つの?」「まあ、世の中には哲学を食らう人間もいるのだ。」

プログラムを哲学する 1. 言及

これから書くのは、言葉や論理と、その意味に関する話だ。フレーゲらによる、物事を厳密に考える言葉の探求は、現代論理学や分析哲学の出発点になった。まずは、その哲学を探りながら、関数プログラミングの話でよく耳にする「参照透過性」という概念を理解することを最初の目標にしたい。

言及

Reference (Stanford Encyclopedia of Philosophy)

普通、記号には表す対象が存在している。記号と記号が表す対象との間にある関係を、言及(reference)という。*1たとえば、「東京タワー」や「港区にある電波塔」という言葉は建造物の《日本電波塔》への言及だし、「港区」や「東京タワーのある区」という言葉は場所の《東京都港区》への言及だ、などという。*2このような、記号の意味とは言及対象のことなのだという考えは、いろいろある意味の捉え方のうちのひとつだ。(直接言及論 Direct reference theory - Wikipedia, the free encyclopedia

意味の合成性原理

Compositionality (Stanford Encyclopedia of Philosophy)

複合表現の意味がその表現の構成要素の意味のみに依拠し決定されるという原理を、意味の合成性原理(compositionality)という。意味の合成性原理は、複合表現の一部分を、同じ意味を持つ別の表現に置き換えたときも、複合表現全体の意味も変わらないということを主張している。

たとえば、次の文を考える。

1. 東京タワーの高さは東京スカイツリーの高さよりも小さい。

文1の「東京タワー」という部分を、意味が同じ「港区にある電波塔」に置換すると、文2ができる。

2. 港区にある電波塔の高さは東京スカイツリーの高さよりも小さい。

意味の合成性原理から、文1と文2は同じ意味だと主張できる。意味の合成性原理は、代入の根拠となっている。

「意義と意味について」

ゴットロープ・フレーゲは、「意義と意味について」(ドイツ語原題: Über Sinn und Bedeutung)において、文の意義(Sinn)と意味(Bedeutung)の区別を主張した。*3

http://www.amazon.co.jp/%E7%8F%BE%E4%BB%A3%E5%93%B2%E5%AD%A6%E5%9F%BA%E6%9C%AC%E8%AB%96%E6%96%87%E9%9B%86%E3%80%881%E3%80%89-%E5%8F%8C%E6%9B%B8%E3%83%97%E3%83%AD%E3%83%96%E3%83%AC%E3%83%BC%E3%83%9E%E3%82%BF-G-%E3%83%95%E3%83%AC%E3%83%BC%E3%82%B2/dp/4326198761www.amazon.co.jp

意義

意味とは言及対象だと考えると、「明けの明星は宵の明星と同じものだ」という文の意味と、「明けの明星は明けの明星と同じものだ」という文の意味は、意味の合成性原理から、同じだということになる。しかし、このふたつは本当に同じ意味なのだろうか。前者は何か新しい知識を与えてくれるのに対して、後者は単なる同語反復にすぎない。フレーゲはそのことを、異なる認識価値(Erkenntniswert)を持っていると表現した。認識価値が異なる文が、同じ意味を持っているということになるが、これはどう考えればよいのだろうか。

フレーゲは、記号に結びつくものとして意味の他に意義があると考えた。「明けの明星」と「宵の明星」は、意義は異なるが、どちらも《金星》を意味している。フレーゲは、通常の命題文の意味は真理値だと考えた。*4「明けの明星は宵の明星と同じものだ」という文と「明けの明星は明けの明星と同じものだ」という文も、意義は異なるが、どちらも《真》という対象を意味している。

副文の意味

フレーゲは認識価値との結びつきである意義と、言及対象との結びつきである意味の区別を主張する中で、同じ表現であっても意味が異なる場合について考えを進めており、副文の意味は真理値ではない場合があると考えている。

コペルニクスは、惑星の軌道は円であると信じた」という真の文について、「惑星の軌道は円である」が偽だからといって、「東京タワーは東京スカイツリーより高い」という別の偽の文を代入して「コペルニクスは、東京タワーは東京スカイツリーより高いと信じた」に変えては、文の真理値が変わってしまう。フレーゲの考え方に従えば、「コペルニクスは、東京タワーは東京スカイツリーより高いと信じた」という文中の「東京タワーは東京スカイツリーより高い」の意味は、真理値ではなく思想だということになる。

このような、同じ表現でも意味が異なる場合があるという考えは、今後referential transparencyの話につながってくる。

意味をもたない表現・意味が定まらない表現

フレーゲは、名詞句を作る副文についても考えを進める。論理的な議論をする上で、表現の意味が一意に存在するということは重要だった。言語のすべての表現について、その意味が一意に定まる性質を、言語の完全性という。

たとえば、「0/0」や「4の平方根」という表現は意味を持たなかったり、複数持っていたりするので、解析学で使われている言語は不完全だ。フレーゲは、言語の不完全性を約定(Festsetzung)によって解決しようとした。フレーゲは「発散無限級数は数0を指示するという約定」を例に挙げている。要は、どのような表現も意味が一意に定まるように、言語を設計するということだ。

この考え方はプログラミング言語ではよく見られるもので、たとえばJavaScriptでは0/0の値はNaNMath.sqrt(4)の値は2と決まっている。プログラミング言語の意味とは式の値だと定義すれば、どのプログラムも一意に値が定まるということがプログラミング言語の完全性ということになる。*5

コラム: さまざまな用語

言葉や記号や意味について議論するのに使えそうな言葉を挙げてみる。

sense, reference, referent, denotation, connotation, extension, intension, signifier, signified, expression, representation, token, idea, image, sign, interpretant, identifier, value, entity, object.

昔から、これらの言葉を使った様々な論が出されているが、その考え方すべてを簡単にまとめることはできそうもない。似た意味で異なる言葉を使っていたり、同じ言葉が少し異なる意味で使われていたりする。おいおいこれらの言葉の関係について考察をしようと思うが、とりあえずは必要な言葉を定義することにする。

*1:referenceの訳語は悩んだ。指示、参照、言及などが候補に挙がった。どの言葉にしても日常の用語と違った意味に聞こえてしまうが、命令を印象させる指示や、物事を参考にすることを印象させる参照などよりは、より自然な表現に聞こえるだろうということで、言及を選んだ。情報科学では、referenceの訳語に参照を使う。訳語に言及を使うことは他ではあまりないが、self-referenceという用語は自己言及と訳されることが多いので、突飛な訳語というわけでもないと思う。

*2:2016年9月3日追記: 英語のreferenceはreferentの意味で使われることがある点で、日本語の「言及」と意味合いがずれているので注意がいる。「表示」と訳されるdenotationも、意味するところは「表示されるもの」なので難しいところだ。

*3:SinnもBedeutungも類義語だが、日本語ではSinnを意義、Bedeutungを意味と訳し分ける場合がある。英語ではSinnをsense、Bedeutungをreferenceと訳すことがある。

*4:命題の真理値は人間の信念に関係なく客観的に決まっているという考えが根底にある。

*5:この定義の上では、JavaScriptは完全でない。たとえば、例外を投げる場合や、無限ループが発生する場合に、式は値を持たない。完全・不完全を議論する上では、何を意味だと考えているかに注意する必要がある。