クロージャを教えるのは苦労じゃ

2月 12th, 2008

大学に入ってすぐの頃、「クロージャって何ですか」と聞いたときの返答がこれでした。
そのときはCのstaticな変数と同じようなものかと理解したけど、
今思うと遠いような近いような……

R6RSという奴は…

2月 10th, 2008

R6RSではR4RSで登場したsyntax-caseが復活すると聞いていました。
確かに、R6RSの9.2節に
「syntax-caseでもdatum->syntaxを使わなければ衛生的なマクロが定義できる(12.6節参照)」
という説明がありましたが、syntax-caseという言葉が登場するのは恐らくそこだけで、
おまけに、R6RSは11章までしかありませんでした。
でも、よく見てみたら参照と書いてあるのは、標準ライブラリ(*)の12.6節でした。
R6RSの本体が90ページ(付録を除いても60ページ)もあるのに、
標準ライブラリの説明も70ページもあります。
英語がろくに読めない私にはあまりにも過酷です。
仕様書が薄いのがSchemeの特徴だったはずじゃ……
(*) Revised6 Report on the Algorithmic Language Scheme — Standard Libraries
—-
でも、syntax-caseが仕様に戻ったというのは嬉しいです。
syntax-ruleだけじゃ、私には使いこなせない気がするからです。
というのも、去年の夏休み、Common Lispでyaccもどきを作ったんです。
ただ、yaccのようにファイルに記述したBNFを読み取ってソースを吐き出すのではなく、
S式として記述してあるBNFを入力とし、Lispのプログラムを吐き出すマクロとして作りました。
例えば、次のような文法の構文解析器を生成したいとします。

EE+T
ET
TT*F
TF
F→<E>
F→i

この場合は、次のように書きます。
(ここでは、構文解析と同時に計算もするものを作ってます)

(setf (symbol-function 'parser)
(make-parser (E (E '+ T) (+ $1 $3)
(T) $1)
(T (T '* F) (* $1 $3)
(F) $1)
(F ('< E '>) $2
('i) $1)))

そしたら、こんな関数が作られます。


#<CLOSURE :LAMBDA (#:G267)
(LET ((#:G266 '(#:G253)) (#:G268 (POP #:G267)))
(LABELS
((#:G265 (#:G269)
(IF (EQ #:G268 '#:G252) (CAR #:G267)
(CASE #:G269
((#:G264)
(CASE #:G268
((#:G230)
(LET (($1 NIL))
(SETF $1 (PROGN (POP #:G266) (POP #:G266) (POP #:G266)))
(LET ((#:G292 (CAR #:G266))) (PUSH #:G268 #:G267) (SETF #:G268 'T)
(PUSH $1 #:G267) (#:G265 #:G292))))
((*)
(LET (($1 NIL))
(SETF $1 (PROGN (POP #:G266) (POP #:G266) (POP #:G266)))
(LET ((#:G291 (CAR #:G266))) (PUSH #:G268 #:G267) (SETF #:G268 'T)
(PUSH $1 #:G267) (#:G265 #:G291))))
(以下略)

まあ、正直いいものとは言いがたいのですが、
とりあえず、動くものを作ることができました。
けど、実はCommon Lispのマクロをまともに使ったのはこれが初めてでした。
それでも問題なく書けたのは、マクロを使ったといっても、それは最初に入力を受け取る箇所だけで、
後は普通にLispの関数を書きなぐっただけだったからです。
だから、ボトムアップに開発を進めることができて、
関数単位でテストができたので、Cなんかで同じものを作るよりも、
圧倒的にデバッグが楽だったと思います。
しかし、これをR5RS通りのsyntax-caseがないSchemeで作ろうとすると、
syntax-ruleでマクロを書く必要があり、
syntax-ruleでは展開コードはテンプレートで記述する必要があり、
テンプレートからは普通のSchemeの関数を呼び出したりはできないので……
と、考えただけでも恐ろしいことになりそうです。
という訳で、Schemeを使ってマクロ展開コードを生成できるsyntax-caseが
復活したことに私は賛成です。(といっても、syntax-caseをいまいち分かってないんですが(笑))

ニコニコ動画でシューティング

2月 5th, 2008

明日でようやく試験も終わりです。
なので、こんなものを作りました。
開く前に注意
「ムービー中のスクリプトが原因で…(中略)…スクリプトの実行を中止しますか?」
というメッセージボックスが表示されますが、ここで「いいえ」を選ぶという問答をなんども繰り返す必要があります。
(私のノートでは10回程でした)

結論:
ニコスクリプトであんまし無茶をやっちゃいけない
ニコスクリプトの開発者の方にはもう少し高速化してもらいたいものです。
あと、もう少し機能を追加して欲しいものです。
最後に、もう少しだけ簡単な文法にして欲しいです。できればS式で。
スクリプトに入れた空白は自動的に取り除かれるようなのですが、
『” “』(二重引用符の中にスペース)のスペースまで取り除くのはどうかと……

R6RSはポータブルじゃない

2月 4th, 2008

R6RSを印刷すると紙の枚数が多くなる。
非常に重い。
持ち運びに不便。
ポータブルじゃない。

ニコニコ動画で三目並べ

2月 1st, 2008

ニコニコ動画のスクリプト『ニコスクリプト』の話。
試験期間中というのもあって(*)、こういうものを作ってみました。

あと、このスクリプトでの簡単なアクションゲームの作り方も思いついたんですが、
残念ながら現状ではLispインタプリタは作れそうにありません。
個人的なニコスクリプトの未公開命令のまとめ

  • 基本
    未公開命令を使う時は行頭にスラッシュをつける。
    処理の列はセミコロンで区切る(二つ目以降の命令にスラッシュは不要)
    『時間::/命令1;命令2;…;命令n』が基本の形
    式はJavaScriptな「気分」で書ける(実際はかなり制約がある)
  • commentTrigger(then:処理の列, timer:SEC)
    コメントが入力された(正確には画面に表示された)ときに処理を実行する。他人のコメントでも処理が実行される
    SEC秒の間のみ有効となり、有効時間内は何度でもコメントの数だけ処理が実行される
  • chat
    commentTriggerの中で使用する『変数』(命令ではない)
    chat.messageにはコメントの内容が入っている
    chat.isYourPostが真の時、そのコメントは現在の視聴者が入力したものである
  • if(when:条件式,then:処理の列)
    条件式は色々書ける(比較は==で。&&等も使用できる)
    ifの中にifを書くこともできる
  • drawText(text:文字列, size:サイズ, color:0xRRGGBB, x:X座標, y:Y座標)
    画面上に文字列を表示する。何もしなければずっと残り続ける
    座標は画面中心を(0,0)とし、指定した座標に文字列の中心がおかれる
    drawTextの戻り値を利用して属性(textとか)を変更できる
    visible属性にtrue/falseを入れて表示/非表示を切り替えられる
    例) t = drawText(text:””,size:30,color:0xRRGGBB,x0,y:0); t.text=”ほげ”
  • 文字列1.indexOf(文字列2)
    文字列2が文字列1の何文字目でマッチしたかを返す
    マッチしなければ-1が返る
    文字列1/2には変数も使用可能
    例) chat.message.indexOf(t.text)

ざっとこんな感じです。あとは、1行に沢山書きすぎると動かないとか。
心を無にして書き続ければそれなりに何か作れるはず。
(*)試験期間中は逃避エネルギーによってプログラミングの効率は普段の三倍まで上昇する

R6RS誤字(結末)

2月 1st, 2008

以前の日記で、R6RSに誤字がある?
と書いたのですが、R6RSの中の人に
「これって誤字ですか?」
とメールを送ってみたところ
「その通りだ」
って返事が返ってきました。
少しSchemeコミュニティに貢献した気分になれました。

括弧と角括弧

1月 31st, 2008

R6RSで角括弧が同義語になったって書いてますが、
どうもリストの場合だけであって、ベクタは違うようです。

<list> → (<datum>*) | [<datum>*]
    | (<datum>+ . <datum>) | [<datum>+ . <datum>]
    | <abbreviation>
<vector> → #(<datum>*)

gaucheではどうなんだろうと思い、試してみたところ

gosh> #[1 2 3]
#[ 1-3]
gosh> (vector? #[1 2 3])
#f

なんだかよく分からないけど、ベクタじゃないということだけは分かりました。

R6RS誤字?

1月 30th, 2008

R6RSの4.1. Notationに次のような記述があるんですが、

Some non-terminal names refer to the Unicode scalar values of the same name: <character tabulation> (U+0009), <linefeed> (U+000A), <carriage return> (U+000D), <line tabulation> (U+000B), <form feed> (U+000C), <carriage return> (U+000D), <space> (U+0020), <next line> (U+0085), <line separator> (U+2028), and <paragraph separator> (U+2029).

carriage returnが2回でてきます。
誤字かと思いErrataを見てみたんですが、まだないようです。
これって単なる誤字なんですかね。

R6RSに登場する言語

1月 30th, 2008

zickです。
R6RSを読んでいると、ふと思ったのですが、
「これは○○言語などと同様である」といった感じで登場する、
Scheme以外の他のプログラミング言語の数が、
R5RSと比べて増えている気がしました。
で、気になったので各言語の登場回数を数えて見ました。
(ただし、謝辞と参考文献は除いています。)

言語 R5RS R6RS
Snobol 1 0
APL 3 0
Pascal 3 0
Haskell 1 4
Algol 5 3
Common Lisp 6 3
ML 2 3
C 2 2
Python 0 3
Smalltalk 0 4
C# 0 3
Ruby 0 4
合計 23 29

登場する言語の種類でみたら、R5RSが8種類、R6RSが9種類。
登場回数で見たら、R5RSが23回、R6RSが29回。
やはり増えているようです。
しかし、APLやSnobolが登場しなくなり、RubyやPythonが登場したというのは分かるのですが、
なんで今更になってSmalltalkが登場したのでしょうか。謎です。

世界初(?) プリンタでlispが動いた

1月 28th, 2008

以前、日記で、pslispについて、


つまり、目標はプリンタで動かすことなんですが、
現状ではGhostscriptでしか動作を確認していません。

と書いていたら、koguroさんが実際に動かしてくれました。
pslispをPSプリンタに出してみた
簡単なリスト操作で6分かかったというのがなんとも生々しいですが、
普通に印刷できているようで感動しました。
koguroさん、ありがとうございます。