Archive for the ‘プログラミング’ Category

ニコ動Lisp 2.0[lambda始動]

水曜日, 5月 28th, 2008

ニコニコ動画のメンテナンスが終わったので、ニコ動Lisp2.0(仮称)が始動しました。

「もっと評価されるべき」タグが付いていたので、文字アトムも評価することに。
もっと評価されるべきの意味が違うという突っ込みもありました。
期待通りの突っ込みをありがとうございます。
それはともかくスクリプトを更新して1分もしないうちに
「ラムダきたー」というコメントが書き込まれたんですよ。
どれだけlambdaが欲しかったんだwwww
まあ、なにはともあれ、lambdaが無事動いてよかった。
普段から「lambdaかわいいよlambda」とお思いの諸兄も安心してニコニコできますね。

prognとかdefunとかLisp的(NOT Scheme的)なスペシャルフォームを持っていますが、
lambdaに関してはScheme的な評価規則となっています。
CommonLispでは次のような式は動作しません。

(((lambda (x)
(lambda (y)
(+ x y)))
3)
4)

というのも、関数適用の第一要素はシンボルか(lambda …)に限られているためです。
一方、Schemeではこの式は正しく動作します。
Schemeでは手続き呼び出しの第一要素を評価したものを手続きとして扱い、その形は問わないからです。
ニコ動LispもこのSchemeの規則に従っています。
そのため、上記式は問題なく動きます。

ニコ動Lispはセル、スタックを自分で管理しているので、
本当はGCを書かないといけないんですけど、サボって書いていません。
評価しすぎると大変なことになるのでご注意を(笑)
……いま気づいたんですが、スタックを自分で管理してるってことは、
call/ccも結構簡単に書けますね。頑張れば。
でも、あまりにソースが汚いので頑張る気は起きません(笑)

あの巫女の絵は誰が描いたのかという質問があったので回答。
あれは私の兄が書いたものを無断で使用しました。
以下私と兄のメールでのやり取り。
zick:
前の一恋とクルルの絵を無断で使わせてもらうよ!
(↑こういった時点で無断じゃなくなったやったね(笑))
兄:
お前・・・・頭、いいな・・・

ニコ動Lisp 2.0[予告および仕様]

水曜日, 5月 28th, 2008

ニコニコ動画で動作するLispインタプリタですが、
ついにlambdaとdefunが完成しました。
もちろん再帰呼び出しも可能です。

(defun f (x) (if (eq x 0) 0(+ x (f (- x 1))))) (f 3)

こんなコードが動きます(ただし、2回に分けて入力してください)。
で、ちゃんとテストもしたし、これで完成だと思い、
確定ボタンを押したんですが、なぜかニコニコ動画から反応が返ってこない。
何回試しても反応が返ってこない。
一旦ログインからやり直してみるかと思い、ログアウトしようとしたら、

メンテナンスのお知らせ
現在ニコニコ動画はメンテナンス中です。
5月28日(水) 13時00分~16時00分(予定)
※都合により変更となる可能性がございます。

ぎゃああああああああああああああああ
ちなみに、スクリプトの確定ボタンを押したのは13時を5分ほど回ったときでした(泣)

**ニコ動Lisp 2.0 仕様**
サポートする関数:
car
cdr
cons
eq (数の比較もこれで行う)
atom
+ (引数は任意個)
– (引数は2つ)
サポートするスペシャルフォーム:
quote
if
progn
lambda
defun
データ:
文字アトム (日本語なども使用可能)
数アトム (入力時は非負整数のみ)
コンス (今のところはimmutable)
注意点:
ドット記法による入力は受け付けない。すなわち、 ‘(a . b) は正しい式として扱われない
セルの数は512個固定であるが、GCは行われない。
0.5秒に1回の処理を行うため、再帰呼び出しを繰り返し使うような式は動画の時間内で評価が終わらない可能性がある。
バグと思われるものがあったら報告してもらえると嬉しいです。
ただし、修正されるまではそのバグは仕様です(笑)

続・ニコ動でLisp

火曜日, 5月 27th, 2008

昨日の動画に書き込まれたコメントを見てみたら、
(+ 1 2) とか (print “hoge”) といった書き込みが多数ありました。
pure lispっていったのに……
特に前者のような数値演算をする式があまりにも多かったので、
急遽、数アトムと+をつくり、ついでにifやprognも作っておきました。
少し気になったので、コメントを
・リスト操作
・数値演算
・printを使用
の3つに分類してみたところ、以下のような結果になりました。
(複数に分類されたり、どれにも分類されなかったものもあります。)
・リスト操作: 32%
・数値演算: 47%
・printを使用: 20%
ちなみに、この集計を取ったのは、数アトムと+を作った後ですが、
半数のコメントはこの改造前に書かれていたものでした。
ちゃんと評価できた式は50%前後といったところでしょうか。
数値計算はともかく、20%もの人がprintを使ったというのが驚きです。
(まあ、よく分からない人が他の人のまねをして、
その結果printが量産されたとも考えられますが。)

話は変わりますが……
ジュンク堂に行ったら、オライリーフェアとかなんとかで、
コースターがもらえました。ヒトデのやつ。
ヒトデのコースターといえば、以前CLANNADのDVDの初回特典に
ついてきたものがあったので、せっかくなので並べてみました。
ヒトデ
今日はヒトデ祭りだぞ!

ニコ動で動作するLispインタプリタ書いたよ

月曜日, 5月 26th, 2008

どうもzickです。
2/1に見た夢をきっかけに触り始めたニコスクリプト(正確にはニワン語というらしい?)ですが、
しばらく触っていないうちに色々と機能が追加されており、なんと手続きが作れるようになっていました。
知らない機能を色々触っていたら、いつの間にかLispインタプリタが出来上がっていました。

2/1に見た夢が4ヶ月ほどを経て正夢になってしまいました。
関係ありませんが、少し前に単位が足りなくて4年生になれない夢を見ました。
こちらの夢は正夢にならないことを祈るばかりです。

*ニワン語メモ*
大体のことはニコニコ動画まとめwikiを見れば分かります。
(Lispインタプリタを半分くらい作ってからここの存在に気づきました。もっと速くググればよかったorz)
とりあえず、ここに載っていないような細かい事項を書いておきます。
[1行の制限]
スクリプトは1行に1024文字まで書くことができます(以前はもっと短かった気がします)。
手続きを作って処理を分割できるので、この制限はあまり問題ないでしょう。
[文字列]
文字列に str[n] のように添え字をつけるとn文字目(0から始まる)の文字が得られます。
一見C言語のようですが、正確にはn文字目の文字のみから成る文字列が得られます。
その文字列自身ではなく恐らくコピーが得られるので文字列はimmutableです。
また、文字列のメソッドindexOfは以前は1引数の関数でしたが、
いつのまにか2引数の関数になってました。詳しくはまとめwiki参照。
[配列]
arr=[1,2,3,4,5] のように大括弧で囲むと配列を作ることが出来ます。
大きな配列を作りたかったら要素を沢山書いたらいいのですが、
要素数を100個ほどにすると動作しません(50個では動作しました)。
配列の要素に配列を入れることができるので、大きな配列が必要な場合はこれを使うのも手です。
(push, shiftを使って動的に配列を大きくした場合どうなるかは未確認です)
[手続き]
再帰呼び出しが可能です。その場合も引数$nが壊れることはありません。
これでループが書けます。恐ろしく便利です。

NScLisperでSHIORI

火曜日, 5月 13th, 2008

先に結論を書いておきます。
以下のものは全く役に立ちません(笑)

SWI-Prologのcoroutining

土曜日, 5月 10th, 2008

SWI-Prologのマニュアルを読んでいたら、面白そうな述語を見つけました。

6.2 Coroutining
Coroutining deals with having Prolog goals scheduled for execution as soon as some conditions is fulfilled. In Prolog the most commonly used conditions is the instantiation (binding) of a variable. Scheduling a goal to execute immediately after a variable is bound can be used to avoid instantiation errors for some built-in predicates (e.g. arithmetic), do work lazy, prevent the binding of a variable to a particular value, etc. Using freeze/2 for example we can define a variable can only be assigned an even number:

?- freeze(X, X mod 2 =:= 0), X = 3
No

( http://gollem.science.uva.nl/SWI-Prolog/Manual/coroutining.html )


freezeは第一引数に未束縛の変数を指定し、
第二引数に『第一引数の変数が束縛されたときに実行されるゴール』を指定します。
上の例ではXが3に束縛された時点で X mod 2 =:= 0 が実行されます。
とりあえず、使ってみました。

?- [user].
test(Y):- write(1), freeze(X, (write(a),Y is X + 1,write(b))), write(2), X = 3, write(3).
?- test(Y).
12ab3
Y = 4;
no

実行順序はこんな感じ。
1) write(1) が実行 (画面に1が出力)
2) freeze(X, (write(a),Y is X + 1,write(b))) が実行 (引数は評価されない)
3) write(2) が実行 (画面に2が出力)
4) X = 3 が実行
5) Xが束縛されるのをきっかけにfreezeの第二引数が実行される
5a) write(a) が実行 (画面にaが出力)
5b) Y is X + 1 が実行
5c) write(b) が実行 (画面にbが出力)
6) write(3) が実行 (画面に3が出力)
私自身はコルーチンについてはあまり知らないんですが、
これはむしろ変数の束縛をトリガとした遅延評価みたいに感じました。
Schemeのdelayがfreezeに対応して、forceが変数の束縛に対応する感じです。
他にもfrozenという述語があり、これは指定された変数をトリガとしている
freezeオブジェクト(?)を取得できます。

?- freeze(X, write(a)), frozen(X, Y).
X = _G397{freeze = user:write(a)},
Y = user:write(a) ;
No

使い道は現在はいまいち分かってません。
他にもcoroutining関連の述語はいくつかありますが、
それらはまたの機会にでも。
(条件を満たしたときに引数の実行を始めるwhenという述語があるんですが、
なぜか上手くいかなかったorz)

Prologで毒電波

火曜日, 5月 6th, 2008

リファラを辿って行ったら素敵なサイトを見つけました。
うかべん 伺的ソフトウェア勉強会統合作戦本部公式情報サイト
伺か関連の勉強会なんてものがあったんですね。
しかも5/5に大阪で開催してたとか。
もっと早く知ってれば参加したのに orz
とりあえず、何かやっておこうと思い、
やっつけですが、Prologで毒電波を飛ばしてみました。
(製作時間3分ほどwww)
Prologで毒電波
よし、なんだかよく分からないけど上手くいったぞ(笑)

PrologのバックトラックとGUI

土曜日, 5月 3rd, 2008

XPCEを使えばPrologで自由自在にGUIが使えるんですが、
そうすると、どうもプログラムがPrologっぽくなりません。
というのも、画面の表示を書き換えたり、
さらには変数の値を書き換えたりするので、
バックトラックを極力避けるような作りになるためです。
GUIとバックトラックをどうにか共存できないかと考えたところ、
マルチスレッドにする方法を思いつきました。

  • 一つ目のスレッドがGUIを用いた入出力などを管理する。
  • 二つ目のスレッドは通常のPrologのプログラムを走らせる。
  • 二つのスレッドはメッセージ通信を行う。

この考えでどうにかならないかと思い試してみました。
XPCE
走らせたプログラムはこんな感じです。

test :-
(test1 ; thread_send_message(main, [println, 'No'])).
test1 :-
thread_self(S),
thread_send_message(main, [println, 'member(X, [1,2,3,4,5])']),
member(X, [1,2,3,4,5]),
concat_atom(['X=', X], Text),
thread_send_message(main, [println, Text]),
thread_send_message(main, [click_wait, S]),
check,
thread_send_message(main, [println, 'Yes']).
check :-
thread_get_message(Msg), !,
Msg == right.

member(X, [1,2,3,4])を行い、Xが適当な値に単一化されると
それを表示し(別のスレッドに アトムprintlnと共にthread_send_messageで送信しています)、
画面がクリックされるのを待ちます
(アトムclick_waitと自分のスレッドIDを送信すると、
画面がクリックされたときにアトムleftかrightが送信されるので、
それをthread_get_messageで受け取っています。)。
右クリックされると、画面にYesと表示して終了します。
左クリックされると、バックトラックが起こりmember(X, [1,2,3,4])が再び実行され、
Xが別の値に単一化されます。Xが単一化できなくなると、
画面にNoと表示して終了します。
……GUIとPrologっぽいのプログラムを共存させようと思ったんですが、
これをのPrologっぽいプログラムといっていいのやら。
けどまあ、とりあえず無事動いたので満足です。
もうすこし抽象化すれば見た目がマシになるかも。

XPCEのbitmapクラス

木曜日, 5月 1st, 2008

PrologのXPCEで遊んだときのメモ。
画像ファイルの読み込みは物凄く簡単。

new(BM, bitmap('hoge.bmp')).  % hoge.bmpを読み込む

しかし、このようにして作ったbitmapオブジェクトはread-onlyとなり、
invert, xor, orといった破壊的なメソッドを呼び出すことが出来ない。
これを解決するには、コピーを作ってそっちを操作すればいい。

get(BM, copy, CopyBM).
send(CopyBM, invert)  % 色を反転させる

SWI-Prologでmulti-threadとsocket

月曜日, 4月 14th, 2008

ここしばらくSWI-Prologで遊んでます。
multi-threadとsocketを使ってechoサーバを作ってみたり。
ソケットに関しては、
tcp_socket
tcp_listen
tcp_bind
tcp_accept
といったそのまんまな名前の述語が用意されています。
マルチスレッドに関しては、
thread_create
という述語でスレッドを作るようです。
今回は使いませんでしたが、
thread_send_message
thread_get_message
という述語を使うことにより、
スレッド間通信ができるようです。
やっぱしErlangと感覚が似ている気がします。
ただ、こういったプログラムではバックトラックも使いませんし、
正直Erlangで書く方が大幅に楽だと思いました。
(まあ、これは私がPrologより先にErlangを触ったからかもしれませんが。)
詳細な情報はこのあたりに載ってます。