ESUG 2014とロンドン観劇

European Smalltalk Users Group Conference に10年ぶりに参加してきました。フレンドリーで、かつ激しい議論を戦わせるだけでの共通認識があるので、楽しい会議である事には違いないです。新しいVMがぽろぽろ出てきていたり、ベンダーも多数来てプロダクトのアップデートをしたり、学生達が発表したりと活気もあります。

帰り道ロンドンで一晩空きがあったので、Gielgud Theatreでやっていた"The Curious Incident of the Dog in the Night-Time"の劇をDan とKatとDanのお姉さんと見てきました。舞台装置がとても創造的で、かつ原作が提示する「少年の成長物語」を余すところなく伝えていてなかなか素晴らしい舞台でした。

The Curious Incident of the Dog in the Night-Time: A Novel

The Curious Incident of the Dog in the Night-Time: A Novel

最近読んだもの

"A 15 Year Perspective on Automatic Programming" by Robert Balzer

http://www.cs.utexas.edu/~idbaxter/cs395T/papers/Balzer85AutomatedProgramming_01701945.pdf

Robert (Bob) Balzerは"history-playback debugger"とか"Dataless Programming"とかに関する先駆的で興味深いアイディアを多数打ち出した人なのですが、なぜかあまり注目度が高くないという人です。後から出てきた同種のアイディアについた名前が人口に膾炙しているわけです。

それはともかく、"Automatic Programming"に関してもいろいろと仕事をしていたわけです。コンパイラではなく仕様からプログラムを作る事、そして仕様を作る事を支援する環境に関しての考察です。

"Papers on Automatic Programming for Numerically Controlled Machines" by Douglas Ross

http://bitsavers.informatik.uni-stuttgart.de/pdf/mit/whirlwind/apt/APT_Reports_Jan58.pdf

Automatic ProgrammingはもともとFortranなどもそう呼ばれていたわけですが、こちらはNC工作機械への入力を生成するという1958年の論文。古いです。

"What's wrong with APL?" by Phil Abrams

http://dl.acm.org/citation.cfm?id=803777

まあ的確な指摘でしょうな。

"Artificial Intelligence Meets Natural Stupidity" by Drew McDermott

http://www.inf.ed.ac.uk/teaching/courses/irm/mcdermott.pdf

私はそれほどAIの話は知らないので(特にこの記事が書かれた当時の文脈など)十分理解できたわけではないですが、タイトルだけでもお腹いっぱいです。

Scratch@MIT

4年ぶりにScratch@MITに参加しています。以前ののんびりした感じよりも、大人がまじめな事をしている集まりの用でもありますが、それぞれの人は本当に元気で面白い事を考えているので、素晴らしいです。

日記を検索したら、私が書いたScratchに関する最初のエントリは2004年4月でした。時は流れます。

http://d.hatena.ne.jp/squeaker/20040417#p1

J言語をOMeta2/Squeakで作る

APLの集まりに参加した関係上、私も処理系の1つぐらいは作らなくてはな、ということで雑用に追われる中(実は転職しました)ちょっと作ってみました。

実装の都合上、シンボルはAPLのシンボルではなく、ASCIIベースでやっているJ言語のものを使っています。

実装に使う言語はOMeta2/Squeakで、パーザーとインタープリターをそれぞれ別のクラスとします。あ、ちなみに世界に蓄積された「効率の良いAPL処理系を作る」ためのノウハウ(http://www.slac.stanford.edu/pubs/slacreports/reports07/slac-r-114.pdf にある"drag-along and beating"とか)とは距離を置き、とにかく簡単な実装とすることを目標とします。

パーザーはJParserというOMeta2クラスのサブクラスとして作ります。

Jの実行単位は「文」と呼ばれているもので、それは簡単に言ってしまえば、「要素」の1つ以上の列です。ですので、文を認識する構文規則は以下のようになります。

sentence =
        element+

ですが、一応認識したもののリストを結果として取り出し、よけいな余白などがあっても動くようにするわけなので、実際の規則は

sentence =
        element+:s spaces -> [{#sentence}, s reversed]

のようになっています。認識した結果は逆順にひっくり返された後、#sentenceというキーワードをあたまにつけたリストになります。

ここで使われている要素を認識するためのelementという構文規則は以下のような感じです。

element =
        "(" sentence ")" | number number+ | number | primitive | name

文を括弧でくくったもの、数字の2つ以上の並び、一つだけの数字、記号、そしてアルファベットで始まる普通の名前のどれか、ということになっています。elementも認識したものを結果としての粉作手は行けないので、実際には

element =
        "(" sentence:s ")"      -> [s]
number:f number+:s -> [{#array. f}, s]
number
primitive:p -> [{#primitive. p}]
name:n -> [{#name. n}]
のようになっています。それぞれ結果はあたまに適切なキーワードをつけたリストです。 まあnumberとかprimitiveとかの規則も定義はしなくてはいけないのですが、それらはまあ簡単なのでここでは省きます。と いうわけで、sentenceとelementという規則を定義することによって、Jのパーザーが完成しました。このパーザーは例えば
(2 3 $ 1 2 3) +/ 4 4 4 
のような入力を食わせると
{#sentence.
  {#array. {#number. 4}. {#number. 4}. {#number. 4}}.
  {#primitive. #/}.
  {#primitive. #+}.
  {#sentence.
     {#array. {#number. 1}. {#number. 2}. {#number. 3}}.
     {#primitive. #'$'}.
     {#array. {#number. 2}. {#number. 3}}}}
という構文解析の結果を出力します。 次はインタープリターです。インタープリターの基本的な動作は http://www.jsoftware.com/help/dictionary/dicte.htm に記述されています。要するに入力を後ろからスタックに積んでいき、スタックトップの近くで還元できる要素があれば還元する、ということになります。OMeta2は要素の後ろの方を処理するという機能がないので、パーザーの方で順序をひっくり返していたのでした。 インタープリターはJInterpreterというOMeta2クラスのサブクラスとして作ります。 JInterpreterはスタックを状態として持ち、入力要素を見るたびにスタックに「シフト」し、還元できるようなら「リデュース」するという動作になるので、これをそのまま書き下して
sentence =
        {#sentence (shift | reduce(false. stack))+} reduce(true. stack)*
                -> [stack last]
と書きます。sentenceキーワードで始まるリストの要素を全部見終わった後にもスタック上に還元すべき要素がまだ残っているかもしれないので、最後には還元できる間ループして(クリーネ閉包*を使う)、スタックトップを結果とします。 shift規則の骨子は
shift =
        ({(#array 
                ({#number anything:n} [n])+:nn
                [JArray new: {nn size} data: nn offset: 0]
        |       #number anything:n [n]):n
        } [n]
        | anything):n
        [stack addLast: n]
というくらいのもののはずです。#arrayキーワードで始まる配列が来た場合は、JArrayというJの配列を表すオブジェクトを作ります。数値やシンボルなどは構文解析の結果そのもので良いです。 ですが、上記のページを見ると副詞(adverb)や接続詞(conjunction)の結合規則について何やら書いてあります。構文解析時にバラバラのままにしておいた+や/のシンボルはどこかの段階で結合させなくてはならないようです。ですので、シフトしようとしたものが副詞や接続詞だった場合には、その時点で読めるだけ読んで結合したものを動詞としてシフトするようにします。 さらに、もともと丸括弧で囲まれていた副文であった場合にはそれを評価しなくてはならないので、それもシフト時にやってしまうことにします。
shift =
        (
          parseVerb
        | {
            (#array 
                ({#number anything:n} [n])+:nn
                [JArray new: {nn size} data: nn offset: 0]
           | #number anything:n [n]):n
        } [n]
        | anything):n
        (
        isInnerSentence(n)
        | [stack addLast: n])
例によってparseVerbやisInnerSentenceの定義は省きます。 還元を表すreduce規則はだいたい
reduce :last =
        {(
                arg:n conjunctions:c
                -> [self pop: 4 andPush: c andPush: n]
        |       arg:r dyadOp:o ~verb arg:l 
                -> [self pop: 3 andPush: (o value: l value: r)]
        |       arg:r monadOp:o (?[last] | (~arg ~conjunction anything))
                -> [self pop: 2 andPush: (o value: r)]
        ):n _*}
        [n]
のようなものです。 というわけで、後は必要となるヘルパーを書いて、パーザーとインタープリターの完成です。 ただ、実際に計算を行う演算子の実装にはまだ手間がかかります。+や-といった2項演算子であっても、引数となっている配列の次元の組み合わせ、そしてランクオペレータの指定するランクによって振る舞いが変わってくるので、その辺に対処したものをSqueakのコードとして書きます。Jの場合は演算子の動作の定義を、JArrayのメソッドとして書いて、左辺と右辺を非対称にするのは気が進まないので、JInterpreterの暮らすメソッドとして "doDyad: op with: l with: r lRank: lr rRank: rr"のようなシグネチャのものとして書きます。 さらには、このような演算子は副詞や接続詞によって際限なく修飾されうるので、Squeakクロージャーを活用して、組み合わせることにします。例えば、+が使われたときに適用される関数は
        Dyad at: #'+' put: [:a :b :ar :br | self doDyad: [:x :y | x + y] with: a with: b lRank: ar rRank: br].
のようにDyadという辞書にしまっておきます。4つ引数があるのは、2つの引数およびそれぞれの引数のランク情報を渡すためです。 そして、例えば一般化された外積を表す2項演算子の'/'は、
        DAdverb at: #'/' put: [:v |
                [:l :r :lr :rr | self outerProduct: v with: l with: r lRank: lr rRank: rr]].
のようにDAdverbという辞書にしまっておきます。入力として"+/"のような組み合わせが現れた場合には、
(DAdverb at: #'/') value: (Dyad at: #'+')
のようにすると、再び4引数のブロックが結果として返るので、それを2項演算子として使うことができるわけです。 で、せっかくSqueakで作った以上、対話的な環境を作らねばなりませぬ。というわけで、Workspaceのサブクラスを作って2,3のメソッドをオーバーライドし、入力したものがJの式として評価されるようなものを作ります。 http://tinlizzie.org/~ohshima/BattleFeverJ.png さらなる発展があるかどうかはかなり謎ですが、まあ記録までに日記にしてみました。

出張

2週間にわたってドイツとイギリスに出張してきました。ドイツはStuttgartとTübingenに近いGäufeldenという街というか村で、共同開発者とハイキングをしながら設計会議をみっちりと。イギリスの方はAPL系配列言語の開発者達が密かに集まってこれまたみっちりとAPLについて語ったり実装をしたりするというCambridgeのTrinity HallでもたれたIverson Collegeなる集まりでした。

Iverson Collegeのほうはさすがにとっても濃い感じでした。中でも、Kという言語とkOSというOS、kDB+というデータベースをやっているArthur Whitneyの書くコードには、その徹底的なminimalismに驚かされました。

私も片手間ながらちょっとしたJもどき言語のパーザーとインタープリタを作り始めました。まあ本格的なものにはなりませんが、ちょっとした遊びに使えるようにはしたいと思っています。

スノッブなイギリス人」のステレオタイプとして、何気ない会話の中で、突如日本文化に関する質問をし、話すに足る人間かどうかを調べる、というものがあります。今回は「侘び寂びは英語に訳すときはなんと言えば良いのだろう」と聞かれました。これは探りを入れてきたというよりは純粋に思いついた質問、と言う様子ではありましたが。とっさに(というかどこかで聞いたことのある)"beauty in imperfection"と答えてその後マクロスの話で盛り上がったりもしてまあ良かったのですが、アウェイでの戦い方はそれなりい経験したなあと思ったりもする旅でもありました。

The Future of Programming Workshop

http://www.future-programming.org/call.html

です。最近はときどきいろいろなプログラム委員になっている気がしますが、これは結構楽しみです。

"Communications Design Group SAP Labs"というのはAlan Kayが音頭取りをして新たに設立した研究グループです。Viewpointsそのものもほぼ飲み込まれた、というかCDGがViewpointsの拡張というか、事実上一体化して活動しています。いろいろと有名な人が入っているのでこれからが本当に楽しみです。

2048リモートコントローラー

2048ゲームがちょっと流行ったところで、

http://gabrielecirulli.github.io/2048/

今更ながらソルバーを作ったりするのも芸がないので、オリジナルのサイトのコンテンツをよそからリモートコントロールできるようにしてみました。

http://lively-web.org/users/ohshima/lively-2-webpage.html

を開け、Generate connect codeのボタンを押した後でdrag this to your bookmark barのリンクをブックマークバーにドラッグします。その後http://gabrielecirulli.github.io/2048/を別のタブで開き、そのタブが表示されているところで先ほどブックマークに登録したブックマークレットを押します。これでLivelyの方に戻るとしばらくして右にあるラベルが"connected"に変わるので、open remote workspaceのボタンを押します。

後は左上の"2"を押すたびに、ゲームの画面が更新されるようになる、はずです。少なくともChromeであれば。

LivelyはSmalltalkみたいな環境なので、リモートコントローラ側の機能をどんどん拡張していけるところが面白いところですし、Robert Krahnの作ったlively2livelyという仕組みがあるので、複数のウェブサイトを自由につないで遊ぶ、ということができるわけなのです。

難しかったところは、KeyboardEventを作った後でそのフィールドに正しい値をセットするところでした。whichプロパティなどはリードオンリーなので、簡単には変えられません。結局のところsetterとgetterを定義してかわす、というのが定番のようで、私のコードは

(function() {var v = document.createEvent("KeyboardEvent"); Object.defineProperty(v, "keyCode", {get: function() {return parseInt(this.keyIdentityfer.slice(2), 16)}}); Object.defineProperty(v, "which", {get: function() {return parseInt(this.keyIdentifier.slice(2), 16)}}); v.initKeyboardEvent("keydown", true, true, window, ' + k + ', 0); document.getElementsByClassName("container")[0].dispatchEvent(v)})()

みたいになっています。おそろしや。