Arcからの挑戦

Arc をリリースしてから2、3日経ったので、もうみなさんとも、それを耳にして何かしらの意見を持ってくれたように思う。
今のところは、評判がどうというほどでもなく、なんかウェブにでてきたみたいだねといった程度だ。
なにしろまだ日が浅いので、 Arc でプログラムした経験談といった高級なものは望むべくもないのだが、私はそれを楽しみに待っている。
それでも、的を射た反応もあった。意義をいくらかでも理解してくれている人たちからの、ファースト・インプレッションだ。

どうやら、これらには特徴的なパターンがあることに気づいた。
Arc についての主たる批判は、書くのに苦労していたわりには大したことないじゃんということだった。
Ron Garret 曰く:

 そして Arc について主な不満: 作るのにずいぶんかかったうえ、あんなに高い目標を立てていたわりには、
 まるで、言語デザインの難問に向かってパントしたようにしか見えない.

いつもなら、批判主義にまともに反駁しようとは思わない。反駁は、書くのは楽しいが、読んでもつまらないものだ。
ただ今回の場合はあえてそうしよう、というのも、Ron やその賛同者たちは 啓発的な間違いをしてくれているからだ。
説明しよう。それとともに、言語デザインについて重要なことがいくつか明らかになるはずだ。

Ron は正しい。私は、どの機能を作るかを選ぶときに、それにどのくらい苦労するか、では選ばなかった。
かわりに、私が使うのは、もっとこう、俗っぽいテストだ:それでプログラムを短くできるか。

どうしてそうするかって? なぜなら、プログラムを短くするために高級言語はあるからだ。
プログラミング言語のパワーは、それで書かれるプログラムの長さに反比例する。
100%確実にそうだとまでは言わないが、マジでそんな感じだ。
もし誰かがこういったとしよう。馬鹿げたことだと思わないかな。
「そのプログラム、君の言語だとコードは10行で、俺の言語だと50行だけど、俺の言語はパワフルだぜ」
こう思わざるをえない: じゃあ、あんたの言うパワーってなんなのよ?

私も、プログラミング言語を測るのに基準となるのはパワーだけなどというつもりはない。
他にも正当な目標はある。例えば、言語をデザインするにあたって、子どもにも学びやすいようにするとか、
効率的なコンパイルをするとか(これは昔ほどには大切でなくなってきているが)、
グループのダメプログラマが何かやらかしても滅多なことにはならないようにするとか。
そういった特別な目的のためにデザインされた言語は別としても、パワーは言語のテストである。

実装が難しいことよりも、プログラムが短くなることを選ぶということは、こうも言える:

 仕事は、自分にとってのコストではなく、ユーザにとっての価値に基づいて決める。

これこそはまさに、デザインの正しい優先順位である。これはプログラミング言語に限らず、誰かに使ってもらうために作るものなら何でもそうだ。

といって、私がやったことはひとつも難しくなかったというのではない。いくつかは私には難しく思えた。
それでも言語デザインにおいて、問題を解くというのは、難しいにせよ易しいにせよ、終着点ではない。よい言語を作ることこそだ。
Arc にとっての本当のテスト -- そしてあらゆる汎用目的の高級言語にとってのテスト -- は、
機能 x があるとか 問題 y を解けるとかではなく、それでプログラムの長さがどうなるかなのだ。

プログラムを短くするといっても、ユーザが実際に書く必要があるものを短くしなくては。
私が Arc を作るときの手口は、それでアプリケーションを書いて、プログラムを一行一行たどることで、
プログラムを短くできるような言語の機能をひねりだすことだった。そして機能を実装しては、それを使ってプログラムを書き直す、その繰り返し。
これは Hacker Newsのソースにあるコメントだ。たまに記録をつけるようにしているのだ。

; results of (codetree "news.arc"):
; 8787, 8760, 8738, 8726, 8823, 8755, 8703, 8628, 8587, 8565
; 8633, 8573, 8552, 8520, 8510, 8498, 8549, 8515, 8684, 9025
; 9573, 12196, 12469, 12648, 12373

(数字がときどき増えるのは、私が News に機能を追加したためだ。)

これが、Arc自身のソースコードがこんなに短いことの理由のひとつだ。自然とそうなった。さっきのと同じことをやったのだ。
ただ、一番優先していたのは、アプリケーションを短くすることで、言語を短くすることではない。
よさそうな機能として、最も顕著だったのは Prolog スタイルのパターンマッチングだ。
相当短くなるので有望に思えたが、結局、便利なのは 2、3の基本的な順列操作(append, remove など)を書くときだけだった。
Prolog は append を書くには素晴らしい言語だ; あとは落ちる一方だ。

Arcを書くうえでのもうひとつの目標は、 McCarthy がはじめた流儀を可能なかぎり継承することだった。
彼は 1960 年の原著論文で、Lisp を作るのに、"公理"(carやcdrやcons)からはじめて、"定理"(assoc や mapcar)へと積み上げるようにした。[1]
どこかに、完全な言語に通ずる、最適な道があるに違いない。それはなんだ? McCarthy の論文は大成功とまではいえないだろう。 その後、言語は彼の院生の手に託されたが、その院生は IBM 704 上で走るインタプリタを作ることに囚われて、 McCarthy の公理的アプローチを続けなかった。
それからというもの、我々は彼らのその場しのぎにつきあわされている。
Steele と Sussman は、 Scheme の研究当初は初心に戻ろうとしていたので、実質的にそれが唯一の試みだったといえる。
そして彼らは、少なくとも 簡潔さ/パワーの観点からは深刻な過ちをいくつか、早いうちに犯してしまった。

これは、開拓する価値がある領域に思える。
それで、私は、公理で下から攻め、実世界のアプリケーションが求める簡潔さで上から攻めることで、最適なオペレータのコアを作り出すことができるだろうと考えたのだ。
いまだ道半ばだが、ゴールははっきりしている。: ごく少ない公理からはじめて、日常で使う完全な言語につながるような、最適な道を見出すことだ。
私は効率性のために妥協をして、チャーチ数を使わないことにした。[2]
私は 1960 年の原著論文の精神をできるかぎり崩さぬように努めた。

公理から言語へ積み上げていくこと自体が目的なのではない。それが最大限の表現力を得る方法だと考えているから、そうしているだけだ。

いまのところ Arc は上手くいっているだろうか? プログラムは、他の言語でやるよりも短くなるだろうか? 測ってみよう。

単純な問題を、挑戦として示すことにしよう。そして、ポピュラーな言語での解答を集めて、その長さを比べてみるつもりだ。

 次のようなプログラムを書け。
 URL said (例えば http://localhost:port/said )は、入力フィールドひとつと、送信ボタンひとつのページを生成する。
 送信ボタンが押されたら、2番めのページとして、"click here." と書かれたリンクひとつのページを生成する。
 それがクリックされたら、3番めのページとして、"you said: ..." と書かれたページにいく。
 ここで ... は、さっきの入力フィールドにユーザがタイプしたものだ。
 ただし、3番めのページは、ユーザが実際にタイプしたものだけを表示すること。
 つまり、入力フィールドの値を URL で渡してはいけない。そうしないと、最後のページの動作をURLで変えるようなことができてしまう。

単純だし、このようなテストに求められるように、これは例として不自然ではない。
Webアプリは、このようなことをいつもやっているのだ。あるいは、何か難解なライブラリ(Arcにあって他の言語にはないような)に頼るわけでもない。Webアプリを書くのに使われる言語なら当然もっているものだけでいい。

これが Arc の答えだ:

(defop said req
  (aform [w/link (pr "you said: " (arg _ "foo"))
           (pr "click here")]
    (input "foo") 
    (submit)))

もし Arc になじみがなければ、私のいうことを信じてもらうほかないが、これはコード上のトリックで圧縮したわけではない。
これが Arc で書くには標準的な書きかたなのだ。

プログラムの長さについて、もっとも意味のあるテストは、行数や文字数ではなく、コードツリー(ソースを表現するのに必要になる木)のサイズだ。

Arcの例のコードツリーは、23ノード:15の葉/字句 + 8内部ノードだ。あなたのお気に入りの言語だとどのくらいの長さになる?

(標準ライブラリをインポートするコードは数えない、もちろん。それらはすでに読み込まれているものとしてよい)

この問題を Arc フォーラム に投稿した。http://arclanguage.org/item?id=722
もしまだ出ていない言語での解や、あるいは出ている言語でも、より短いとか、より正しい解があれば、追加してほしい。言語を、Arcとだけでなくお互いに比べあうと面白いだろう。

Notes

[1] "Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I," CACM, April 1960.

http://www-formal.stanford.edu/jmc/recursive/recursive.html

[2] かつて、整数nを長さnのリストで表現しようとして、さんざんな目にあった。


訳:gemma

議論

Past comment(s)

cut-sea (2008/02/25 21:23:50):

まずKahuaでそのまま書いたらどうなるか。

(define (page . args)

  (html/ (apply body/ args)))

(define-entry (said)

  (define (end say)
    (page (p/ "you said:" say)))
  (define (here say)
    (page (a/cont/ (@@/ (cont (lambda _ (end say)))) "click here")))
  (page
   (form/cont/ (@@/ (cont (entry-lambda (:keyword say)

(here say))))

     (input/ (@/ (type "text") (name "say")))
     (input/ (@/ (type "submit") (value "SAY"))))))

(initialize-main-proc said)

cut-sea (2008/02/25 21:26:01):

ぐはぁ、しまった。

(define (page . args)
  (html/ (apply body/ args)))

(define-entry (said)
  (define (end say)
    (page (p/ "you said:" say)))
  (define (here say)
    (page (a/cont/ (@@/ (cont (lambda _ (end say)))) "click here")))
  (page
   (form/cont/ (@@/ (cont (entry-lambda (:keyword say)
                            (here say))))
     (input/ (@/ (type "text") (name "say")))
     (input/ (@/ (type "submit") (value "SAY"))))))

(initialize-main-proc said)

cut-sea (2008/02/25 21:30:36):

あ、もしかしてArcのコードはHTML全体を書いてないのかしらん。 だとすれはここまでは許されるのかな?

(define-entry (said)
  (define (end say)
    (p/ "you said:" say))
  (define (here say)
    (a/cont/ (@@/ (cont (lambda _ (end say)))) "click here"))
  (form/cont/ (@@/ (cont (entry-lambda (:keyword say)
                           (here say))))
    (input/ (@/ (type "text") (name "say")))
    (input/ (@/ (type "submit") (value "SAY")))))

(initialize-main-proc said)

cut-sea (2008/02/25 21:36:57):

ただ、多分PGの問題にしているのは、このレベルの話じゃなくて、 1画面挟むことによってコンテキストをどう保持するかを伺っているな。

URLを使っちゃいけないとなると、

  1. セッションで保持するか
  2. ページにhiddenで埋め込むか
  3. それとも継続を使うか

でもどれで書いても大差はつかないんじゃないか?と思ったんだが。 もちろん、Arcほど短かくしようと思ったら、もうちょっと@@/の cont clauseに工夫が必要だけどさ。

shiro (2008/02/25 21:40:04):

ArcはあれでHTMLを出してくれるようになってるはず。だから結局言語の話をしてるんだかフレームワークの話をしてるんだかわからない。 私が書いたのはこれ: http://news.ycombinator.com/item?id=108583

ただ、これがきっかけでいろんな人が実装してフレームワーク総覧みたいな感じになったのはおもしろい。 http://news.ycombinator.com/item?id=108433 にいくつかある。あとブログで書いてる人が何人もいたはずだけどまとめてないや。

shiro (2008/02/25 21:41:28):

ああ、それで、(@@/ (key value) (key value) ...) って (@@/ key value key value ...) でいいんじゃないかなあとかちょっと思った。

cut-sea (2008/02/25 21:58:32):

そうですね。 あとはinput系でtype clauseくらいは必ず指定するから aliasがあってもいいのかもしれないですね。 kahua-ekahiにはそれっぽいのあったようだし。

Post a comment

Name:

Tags: 継続, 翻訳, 読み物

More ...