Archive for 8月, 2008

凄い人見つけた

日曜日, 8月 31st, 2008

Lispのひび
なんかね、13歳でLisp処理系作ってるらしいですよ。
私が13歳の頃はもぐらたたきを作るのが精一杯でしたよ。
それに引き換え、最近の若い人は凄いですね。
私もCで簡易Schemeインタプリタを作ったことがあるので、
返事がもらえるかは分かりませんが、気になったことを適当に書いておきますね。
* リーダはどうやって書いてるんだろう

readを追加。数値アトムを読み込むことに成功。
80文字までのバッファでfgetsでstdinから読む。長すぎる場合、sskipが内部でバッファ切り替えなどもやるような仕組みでLispの本と同じ。
(T216の現状)

アトム読み込みのとき、isspace(..)の代わりに*.. == ‘ ‘と書いていて間違いだった。改行とかも考慮するんだぁ。
後はリストを上手く読み込むように再帰構造を作るだけ。
(isspace)

とのことですが、関数readが括弧に出会ったら、再帰呼び出しを使ってるんでしょうか。
quoteのsyntax sugarをまだ作られていないとのことですが、
再帰呼び出しを使ってるのであれば、quoteのsyntax sugarはすぐに作れます。
readしてあとでquoteで覆うだけです。
でも、Cで書くなら、再帰呼び出しに頼らず、自分でスタックを持った方がいいかもしれません。
* GCどうするんだろう

GCって意外と簡潔に実装できるものだったんだ。
全体の状況と使用中の状況の差異を確認して、回収するだけなのか。
(GC)

一見難しそうに見えて、実は簡単…と見せかけてやっぱりやっかいなのがGCかと思います。
基本的には現在の環境から辿れるものを残して、それ以外を全て回収すればいいのですが、
問題となるのは、C側の変数しかもっていないオブジェクトです。
適当な例を挙げますと、

LObject *list2(LObject *x, LObject *y)
{
LObject *c1, *c2;
c1 = cons();
c2 = cons(); /* もしここでGCが発生したら? */
set_car(c1, x);
set_cdr(c1, c2);
set_car(c2, y);
set_car(c2, NIL);
return c1;
}

コメントの通り、c2のためのconsingの最中にGCが発生したときに、
どうやってc1のもつコンスをGCの魔の手(?)から守るのか。これが結構問題です。
手っ取り早く解決したいなら、

c1 = cons();
push_obj(c1); /* pushしたらGCで回収されない */
c2 = cons(); /* もしここでGCが発生したら? */
/* 中略 */
pop_obj(c1); /* 保護を解除 */
return c1;

みたいなコードを書くのが楽かもしれません。
(タイプ数は増えるのである意味非常に面倒ですが(笑))
* 変数はどうやって実現するのか
ローカル変数をうまく作るにはスタックを使えばよさそうですが、
無限エクステンドを実現するには、それだけでは少々問題があります。
「環境リスト」というものを作ればこの辺は楽に解決できます。
(ただし、速さを考えるのであればこの実装方法は少々問題があるんですが(笑))
* 関数はどうするのか
五関数や四則演算が動くと楽しいんですが、次に問題になるのが関数です。
なんでもいいから動けばいいやというのであれば、
prognさえ作れればほぼ完成です。
引数をどうにかして渡してしまえば関数の本体をevalするだけですから。
しかし、厄介なのが、どうやってクロージャを実現するかです。
(まあ、LISP 1.5にクロージャはありませんが、どうせなら作るべきでしょう。)
これは調べるところを調べれば答えが載っているのですが、
自分で考えてみると非常に面白いかと思います。

CLのスペシャルに秘められた罠(?)

日曜日, 8月 31st, 2008

quoteとかsetqとかifといった特殊な制御に用いるためのシンボルって「special operator」だったんですね。
今までずっとこれらのことを「special form」だと思い込んでいました。
special formはspecial operatorを使った式のことを指すらしいです。
(CLHS Glossaryに詳しく書いてます)
今までなんでこんな勘違いをしてきてそして気づかなかったのか非常に謎です。
私がはじめて読んだCLの本である『ANSI Common Lisp』にもしっかり「特殊オペレータ」と書いてますし、
最近読んでいる『実践Common Lisp』にも「特殊オペレータ」という語が使われています。
見事なまでにスルーしてました。
しかし、よくよく考えてみるとCLtL2にはspecial operatorという語が登場しません。
それどころか、関数やマクロの説明として次のような記法を使っています。

symbol-value symbol [関数]
quote object [特殊形式]

symbol-valueの横に[関数]と書いてあり、実際にそれが関数なんだから、
quoteの横に[特殊形式]と書いてあればquoteは特殊形式(special form)ではないのでしょうか。
と、それっぽい言い訳を考えてみたんですが、

もし最初の要素が表5-1に現れたシンボルのいずれかであれば、
そのリストは特殊形式(special form)と呼ばれる。
(5.1.3 特殊形式)

という風に、式全体のことを特殊形式と呼ぶと明記されてました。
なんてこったい/(^o^)\
しかし、quoteなどのシンボル自体をspecial formと書いてある本を何処かで読んだ気がするので、
色々と探し回ってみました。そしたら、bit1985年4月号にこんな記述を見つけました。

5. 関数とスペシャル・フォーム
MacLispなどのFSUBR関数にあたるものは、Common Lispではスペシャル・フォームと呼ばれる。
しかし、スペシャル・フォームはCommon Lispの意味での関数ではない。
あとで述べるように、関数の引数は必ず評価されるのに対して、スペシャル・フォームの引数の
評価の方法はスペシャル・フォームによって異なる。

(setq)         ; 何もしない
(setq x 1)     ; 変数xに1を代入
(setq x 1 y 1) ; xとyに1と2を代入

は全てsetqという名のスペシャル・フォームであるが、変数に対応する引数は
当然のことながら評価されない。ユーザがsetqという名前の関数を定義していけないという
規則はないが、たとえ定義できてもsetqで始まるリスト・フォームはスペシャル・フォームとして評価され、
関数定義は無視されるはずである。
スペシャルフォームは表3の18個が固定されており(以下略)
(湯淺太一・萩谷昌己, Common Lisp入門 1, bit, Vol. 17, No. 4, 1985)

この説明ではspecial operatorを使った式自体のことをスペシャル・フォームと呼んでいる一方で、
「setqという名のスペシャル・フォーム」の表現が使われています。
また、表3にsetq, ifなどが「スペシャル・フォーム」として挙げられています。
わーい、天下の湯淺先生と萩谷先生がそういったんならいいじゃないかと喜んでいたら、
実はこの連載の翌年の1986年にお2人が書かれた『Common Lisp入門』にて

2. スペシャル・フォーム
次の記号のどれかを第一要素とするリスト。
block macrolet(以下略)
(1.5 評価とフォーム)

special operatorはもはや「記号」としか書かれなくなりました。
他の箇所を読んでも「setqと呼ばれるスペシャルフォーム」みたいな表現は一切ありませんでした。
なんてこったい/(^o^)\
結局、quoteやsetqといったシンボルのことをspecial formというのは単なる間違いだったのか、
それとも昔はそう呼んでいた時期があったのか、非常に気がかりです。
話は変わりますが、Common Lispは、スペシャル変数があるのに、
なんでスペシャル関数がないんだという、どうでもいいことに気づいてしまいました。
ほんと何でないんでしょう。使い道がないからなのか、スペシャル変数で代用できるからなのか…

禁断の乗り物CDR(クダー)の謎を追え!

日曜日, 8月 31st, 2008

データを入れるところが2つある箱をコンスセルという。
左側の入れ物がCAR(カー)で右側がCDR(クダー)。
どうして左側がCARなのか分かる?
車は左側通行だからさ!

Lisp初学者が一度は聞くことになる(と私は思い込んでいる)決まり文句です。
しかし、ここで誰もが疑問に思うのが「CDR」の存在です。
CARが左側通行の乗り物ということは、CDRという右側通行の乗り物があるのでしょうか。
しかし、CDRの正体を尋ねてみても、
「そんなCDRらないことを聞くな。」
と、お決まりの返事をされ、結局CDRの正体を教えてくれません。
ひょっとしたら皆が決して触れようとしない、「クダー」という名の乗り物が存在するのではないのか。
そして、真のLisperのみが隠れてクダーに乗っているのではないか。
そう考え、私なりに色々と想像してみました。
「クダー」という独特の響きや、皆が触れようとしないという事実から察するに、
従来の乗り物とはまったく異なるものではないのでしょうか。
そんなことを悶々と考え、出た結論がこれです。

▲ぼくの考えたクダー

▲クダーに乗車する図
あ、車とは異なるので「乗車」という表現は間違っているのかもしれません。
まあ、そんなことはこの際どうでもいいので放っておくことにします。
それから、乗り物であるからにはいろんなカラーリングがあるのでしょう。
きっと並べてみたらこんな感じです。

▲クダーいろいろ
これはあくまでも私の想像図ですが、きっと本物のクダーからそれほどは遠くないでしょう。
クダーに乗ったことがある、もしくは乗っている人を見かけた方は是非私までご連絡下さい。
あ、CDRはContents of Decremental part of Registerの略という説もありますが、
きっとこれはクダーの存在を隠すために意図的に流された噂でしょう。
いわゆる「政府の陰謀」というやつですよ。騙されてはいけません。

第14回 慢性的CL勉強会[予習]

金曜日, 8月 29th, 2008

久しぶりにCL勉強会の予習。
今回のお題は「The Common Lisp Cookbook – Functions」だそうです。
今回の資料の内容は大体は知っていることだったので、
細かいところを気にしてみることにしました。
- lambdaの話

  • 関数を返す関数のコードがCommon LispとSchemeでは結構違う
  • 関数型のオブジェクトを作るには特殊形式functionをlambda式に適用する
  • lambdaマクロを使うこともできる

CLtL2によると

car部がlambdaであるリストは関数型ではない。
また、いかなるシンボルも関数型ではない。
しかしながら、関数引数を受け付ける標準Common Lisp関数は
シンボルやそのcarがlambdaであるリストを受け入れ、自動的にそれを関数に強制型変換する。
(2.13 関数)

function fn
もしfnがラムダ式であれば、レキシカルクロージャが返される。
(中略)
function特殊形式の結果は、常にfunction型になること<90>を議決した。
(7.1.1 参照)

とあります。
ここまで読んで疑問に思ったんですが、CLtL2には「lambdaマクロ」の存在が載っていません。
それどころか、funcallの説明において

funcall fn &rest arguments
functionはsymbol型かfunction型のみ許されること<90>を議決した。
ラムダ式は、もはや関数の引数として受け付けられない。
つまり、ラムダ式を陽に引数フォームとして記述する際には、
function特殊形式で囲むか、省略形の#’を前置しなければならない。
(7.3 関数の呼び出し)

なんて書いてます。
そうなると「(funcall (lambda (x) x) 3)」のような式はCLtL2的にはエラーとなるんでしょうか。
一方、CLHSにはしっかりとlambdaマクロのことが書いてありました。

This macro could be implemented by:

(defmacro lambda (&whole form &rest bvl-decls-and-body)
(declare (ignore bvl-decls-and-body))
`#',form)

(Macro LAMBDA )

この定義は分かりやすいですね。
- セルの話

  • シンボルは2つのセルをもつ
    • 値セル(value cell) => シンボルに束縛された値を持つ
    • 関数セル(function cell) => シンボルの(大域)関数束縛の定義を持つ?(*)

(*) function cell – can hold the definition of the symbol’s (global) function binding.
CLtL2で値セルと関数セルの説明を探して見ましたが、見つかりませんでした。
代わりに見つかったのがこんな文章。

シンボルの重要な用途として、プログラムの名前として用いることがある。
処理系作成の上からは、変数の概念を実現するために、シンボルのある種の要素を用いるのが
望ましい場合がしばしばある。symbol-valueおよびsymbol-functionを参照して欲しい。
しかしながら、実現の方法は他にもある。したがって、そうしたありうる要素についてはここでは述べない。
(10章 シンボル)

ちなみに、CLHSの用語集にはvalue cellfunction cellがしっかりと載っていましたが、
Cookbookとほぼ同じ内容で、これといって目新しいことは見つかりませんでした。
- カリー化
あと、最後に載っているカリー化関数が気になりました。
&restがあるから、引数を複数取れるけど、これってcurry化っていえるんでしょうか…
まあ、それは置いておいて、appendを使ってるあたりがLispっぽくて面白かったです。

今日は観鈴ちんがゴールした日なのでGoogle Mapでゲーム作った

木曜日, 8月 14th, 2008

昨日気づいたんですよ。
Google Map APIを使えばゲームが作れるんじゃないかって。
地図の上で車を走らせたり、飛行機を飛ばすといった、
地図と連携したゲームじゃなくてもっと単純なゲームを。

遊ぶ

AIRを知らない人には本当に意味が分からないかと思います。。
そして、AIRを知ってる人も結局は意味が分からないかと思います。
(追記)
Google Mapなのが分かりにくかったので、
縮尺を変えて露骨に地図を表示するように変更。

適当にLispネタ

火曜日, 8月 12th, 2008

キーボードの「8」のキーが壊れて以来、
ろくにLispのプログラムを書いてないので、適当にネタを拾って、
忘れないように書いておきます。
以下は、2chのLisp Scheme Part23より。

131 :lischemep ◆/uyHCgG7qA :2008/08/10(日) 23:28:50
都内で初心者向け勉強会を模索しようとしております。
以下想定です。
こうしたらいいとかありましたらどんどん提示して頂けたら幸いです。
・大学生のLisper/Schemerを先生として呼ぶ
・上記のため会費をとります。
・場所は以下を想定。(1h:1400~2300円くらい+各自1ドリンク)
ttp://www.ginza-renoir.co.jp/miyama/
・スキルがバラバラになるため基本的に自習を想定
(同スキルの人と課題本を決めてチーム学習する等は自由です)
・参加条件としてキーボードがサクサク打てる程度。処理系を入れるノートパソコン等。
・開発環境構築から指導の予定
参加者希望予定者がいらっしゃいましたら、
lischemep at gmail.com
まで下記を記入して送ってください。
使用希望の
・希望日(参加頻度:必ず参加、月1希望、仕事のため不定等)
・希望参加費
・OSとバージョン
・エディタ
・処理系
(↑処理系は希望なければおまかせと書いてください)
また先生やってみたいという方は、下記を記入して送ってください。
・希望日(開催頻度も)
・希望報酬額(時給換算、月XX円等)
・対応できるOS・処理系・エディタ


あと、学生を講師にするのに、金を払うという発想はなかった。
お金という直接的なものを渡すのはなんだか生々しい気が…
(終わった後に宴会開いて、講師は宴会費無料とかだったら個人的には嬉しいんですが(笑))

149 :デフォルトの名無しさん:2008/08/12(火) 00:57:31
>>145
国立大は社会人受入れに寛容
なようなので正規に聴講生の
手続きをとって試験も受けて
単位もとりたいです。
でも、地方の大学でSchemeを
使った講義があるところは
限られてるみたいです。


うちの大学はSchemeの講義なんてないよなーなんて思ってたら、
実はとある授業で部分的にやっていたようです。
試験問題にSchemeの問題が出てきて気づきました。
(なんで授業中に気付かなかったって? そりゃ授業に行ってな(ry…)

161 :デフォルトの名無しさん:2008/08/12(火) 02:47:46
>>159
最初の頃はFSUBR + EVALで一々手で書いた。
パターンが出来上がったのでdefmacroになった。
>>156
> 自習だとつまらないことでつまづいて長い時間考えることがあるからです。
本当はそれが大切なんだけどね。
より深く理解するし、それが出来る人が継続もできる。
壁に負ける人はいつも負け続ける。


最初の頃はFSUBR + EVALで一々手で書いた。」ですか。
私は自分でインタプリタを作るときはいまだにこれです orz

話は変わるんですが、「実践Common Lisp」の脚注に

*10 大雑把に言うとMODはPerlやPythonの%演算子と等価であり、REMはCやJavaの%と等価だ
(記述的に断っておくと、Cにおける%の振る舞いはC99まで規定されていない)。
P118 10.4 数値比較

なんてことが書いてあったんですよ。
Cでは負の数の剰余はどうなるか定められてないと思い込んでいたら、
実はC99でしっかりと決まっていたんですね。

夏の不幸 ~2008~

日曜日, 8月 10th, 2008

キーボードがね、破損したんですよ。
PCの前に座ってる状態で本をとろうとしたら、
本の角が「8」のキーに直撃して…
keyboard
むき出しの状態でも一応、押せるんですが、非常に押しにくい。
日本語キーボードの「8」といえば、「(」のキーでもあって、
これが押しにくいとLispのプログラムが非常に書きにくい。
「8」のキーを前に泣く日々がしばらく続いたと思ったら、
雷が近くに落ちてきて、ASDLモデムが壊れました。
現在使えるネット環境はWILLCOMによるダイアルアップ接続のみ。
非常に悲しくなってきます。
それから、オムライスを作ろうと思ったら、
1. 少々変な形になった
2. 中身が若干はみ出してる
3. 真ん中に貯金箱の穴みたいな穴をあけてしまった
という非常に微妙な出来に…
om
何よりも悲しかったのが、途中でケチャップが無くなって、
完成後のオムライスに文字が書けなかったことです。
せっかくS式でも書こうと思ったのに…
最近あった良かったことといえば、
スーパーでお一人様1パック限りのタマゴの最後の1パックが買えたことぐらいですよ。
もうすぐ観鈴ちんの命日だし、ほんとどうしたらいいのやら。

あ、リトルバスターズ(以下㍑)のエクスタシーですが、
新シナリオ3つはクリアしました。
それにしても、あのオトナシーンで挿入されるBGMどうにかならないんですかね。
いきないり
「しゃらららららうーわー…えくすたしー…えくすたしー」
とかいうコーラスが流れたら、
思わず大笑いしてしまうんですが。
曲名を確認したら「Sha La La Ecstasy」という
あまりにそのままな名前で、また笑ってしまいましたし。
Keyのゲームは随所に笑う場所を用意していますが、
まさかオトナシーンで笑わされるとは思ってもいませんでしたよ。
3つのシナリオの中で一番印象に残ったのは朱鷺戸さんシナリオでした。
(!!!以下ネタバレ注意!!!)
あのシナリオだけ時間軸がどうなってるのか良く分からないんですよ。
「あや」の身にあの事故が降りかかったのは恐らく冬でしょう。
そうなると修学旅行の時期とはずれています。
修学旅行まではかろうじて生きていたのか、
それとも死んでからでもあの世界に干渉できたのか。
私としてはいまいちここが分かりません。
おまけに、シナリオの「オチ」の部分ですが、あれが現実世界の出来事とすると、
時間が逆戻りしたことになるんですよ。おまけに記憶まで保ったまま。
これはさすがに㍑の世界観としてないだろうと私は考えています。
そうなると、あれはあやの死ぬ間際の妄想でしょうかね。
㍑のシナリオは、分かりやすいハッピーエンドが多いんですが、
この朱鷺戸さんシナリオだけはどうも毛色が違うんですよね。
オチについては色々解釈があるかもしれないけど、
まあ結局はバッドエンドしか待っていないのかなといった感じで…
私としては㍑で一番面白いシナリオかと思いました。

夏休みはじまたー

金曜日, 8月 1st, 2008

いつの間にか試験が終わって夏休みになりました。
わーい。
そんな訳で、プログラミング欲がゲーム欲に負けて昨晩はエクスタシーな日になりましたよ。ええ。
とりあえず、朱鷺戸さんかわいいよ朱鷺戸さん(*´Д`)
といった感じでした。それにしてもよくゲームオーバーになりました。
多分、Key史上最も沢山ゲームオーバーになる(可能性が高い)シナリオです。
それから、終わったあとのもやもや感はAIRのオチを見たときに似てます。
あと、性能の悪いマウスやノートPCのタッチパッドなんて使ってたら、
ミニゲームが死ぬほど大変です。というか、死にます。冗談抜きに。

CLで作っているWikiですが、必要最低限の機能が完成したので、
こっそりと身内に公開して、苛めてもらってます。
いまのところ、突然落ちたりすることはないようです。
この夏の間に一般に公開しても大丈夫なものにしたいものです。
前のエントリーでCLの改行コードについて書いたら、
色々とお話を聞けたので、簡単にまとめておきます。
*行末のCRを消す*

;; deleteを使う
(delete #\Return line :from-end t :end (length line) :start (1- (length line)))
;; string-trimを使う
(string-trim '(#\Return) line)
;; string-trim-rightを使う
(string-trim-right '(#\Return) line)

他にもadjust-arrayを使う方法などがあるようです。
*文字#NewlineをCRLFとして扱う*

;;external-formatに指定 (CLISP only)
(make-encoding :charset "Shift_JIS" :line-terminator :dos)

ただ、ストリームの改行コードをCRLFとして開くと、
#\LinefeedもCRLFとして扱われてしまうみたいです。恐ろしや。
こうなると、LFだけを出力するのが面倒になるとか。