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

適当に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でしっかりと決まっていたんですね。

夏休みはじまたー

金曜日, 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だけを出力するのが面倒になるとか。

Common Lispと改行コード

水曜日, 7月 30th, 2008

CLでread-lineを使ってファイルを読み込んでいるとき気づいたのですが、
read-lineは

改行によって終了された行を読む。
これは行を文字列として返す。
(改行文字を含まない。)
(CLtL2日本語版第2版より)

という風に説明があったのですが、
#\Linefeed(LF)は読み飛ばしてくれるものの、
#\Return(CR)が思いっきり残っていました。
ストリーム開くときに:external-formatみたいな感じで、
改行コードも指定できたりしないんですかね。
読み込むときは改行コードの判定処理をする必要があるのであれば、
結局自力でなんとかしないといけないとは思いますが、
書き込むときは~%一発で済ませたいものです。


そうそう、リトルバスターズ エクスタシーですが、
プログラミングをしたいという欲求に負けてしまい、
現在、朱鷺戸さんに殺されかけるところまでしかやってません。
それにしても、朱鷺戸さんのBGMがKeyの過去のアルバムにあった
「駆ける」だったのが一番驚きました。

with-output-to-stringと文字コード

日曜日, 7月 27th, 2008

Common LispでWebアプリのお話。
POSTで日本語(UTF-8)を含んだ文字列を送信すると、文字化けしてしまったので、
原因を調べてみると、URLデコードを行っている関数が犯人のようでした。

(defun url-decode-string (s)
(with-output-to-string (out)
(do ((i 0 (1+ i)))
((>= i (length s)) out)
(let ((c (char s i)))
(case c
(#\% (setf c (code-char (parse-integer s
:start (+ i 1) :end (+ i 3)
:radix 16 :junk-allowed t)))
(unless (null c) (write-char c out))
(incf i 2))
(#\+ (write-char #\Space out))
(otherwise (write-char c out)))))))

outの文字コードがしていされていないのが原因だと思うんですけど、
with-output-to-stringでは:external-formatキーワードは指定できないようです。
ストリームを開いた後に文字コードをしている方法はないかと調べてみたら、
system::set-stream-external-formatなる関数があったのですが、
string-streamには使用できないみたいです。
色々苦心してみましたが結局解決策が見つからず、
一旦バイト列に入れてから文字列に変換することにしました。

;;; CLISP only
(defun url-decode-string2 (s)
(let ((arr (make-array (length s) :element-type '(mod 256))))
(do ((i 0 (1+ i))
(j 0 (1+ j)))
((>= i (length s))
(ext:convert-string-from-bytes arr charset:utf-8 :end j))
(let ((c (char s i)))
(case c
(#\% (setf c (parse-integer s
:start (+ i 1) :end (+ i 3)
:radix 16 :junk-allowed t))
(unless (null c) (setf (aref arr j) c))
(incf i 2))
(#\+ (setf (aref arr j) (char-code #\Space)))
(otherwise (setf (aref arr j) (char-code c))))))))

ext:convert-string-from-bytesという関数がバイト列を文字列に変換してくれます。
バイト列に文字コードを指定して文字列を直す関数があるのは非常に便利ですね。
残念ながらCL標準ではないようですが、大抵の処理系にはこの手の関数があるようです。

サーバサイドでCommon Lispを使いたい!

日曜日, 7月 20th, 2008

今日は風子の誕生日ですね。
風子、誕生日おめでとー。
まあ、それは置いといて、
サーバサイドでCommon Lispを使いたい!

*サーバでCLの処理系を動かす*
まず、どうやってCLの処理系を動かすか、少し考えてみました。
1. CGIとしてCLを走らせる (恐ろしく遅い予感)
2. 何か専用のモジュールとか使う
3. 頑張って何とかする
で、調べてみたら、mod_lispというものがあるそうです。
FreeBSDならportsから簡単に入れることが出来ます。
これは、Apacheにきたリクエストを「Lispサーバ」に渡し、Lispサーバからのレスポンスを
元のレスポンスとして返すものです。Reverse Proxyのようなもの?
この「Lispサーバ」は、mod_lisp専用のプロトコルを話すCLのプログラムです。
これは、Apacheと同一マシンで動かしても異なるマシンで動かしてもいいようです。
ここで、少し疑問。
mod_lispという名前の割には全然Lispが関係ない気がします。
なんというかLisp『でも』使えると言った感じが…

*CLで書かれたWebアプリケーション*
CLで書かれた便利なものはないかと探してみたら、
CL-Wikiと、CLikiというものを発見。
CLikiは色々出来る半面、導入が面倒な(気がした)ため、CL-Wikiを使ってみました。
これは、Wikiだけではなく、HTTPサーバの役割も果たすようです。
上記サイトからCL-Wikiのソースをダウンロードし展開し、CLISP上で
> (load “start.lisp”)
とすると、ポート8080にCL-Wikiのサーバが立ち上がりました。
試しにブラウザから127.0.0.1:8080にアクセスすると無事表示されました。
次に、Apacheと共存させるために、mod_lispを入れた後に、http.confに次のような内容を追加。

#lisp
LoadModule lisp_module /usr/local/libexec/apache22/mod_lisp2.so
LispServer  127.0.0.1 8080 "cl-wiki"
<Location /lisp>
SetHandler lisp-handler
</Location>

これで、127.0.0.1/lisp/にアクセスがあると、リクエストがCL-Wikiに飛ばされますが、
このままでは動作しません
最初に書いたとおり、mod_lispは独自のプロトコルを使うため、
CL-Wikiの話す言葉をHTTPからmod_lispのものに書き換える必要があります。
とりあえず、必要そうなところを適当に書き換えたところ、
部分的ではありますが、無事CL-Wikiが動作しました。
ところで、勝手にソース書き換え単ですが、CL-Wikiのライセンスってどうなってるんでしょうか。
調べてもどこにもライセンスが書いてない気が…

*誰かエロい人教えて*
ちょこっと遊ぶ分にはうまく動いたようですが、
実際に外部に公開する場合、このやり方で大丈夫なんでしょうか。
CLを使ったWebサービスってどうなってるんだろう…
(AllegroCLのあれこれを使うっていうのは無しで(^^))

(追記)
CL-Wikiの作者のonjoさんにCL-Wikiを自由にあれこれする許可を頂きました。
ありがとうございます。

CLでプログラム書いた

月曜日, 7月 14th, 2008

最近少しずつですがCLの勉強を続けていますが、
本やらを読むだけで一向にプログラムを書いていなかったんですが、
突如CLのプログラムを「書かなければならない」という珍しい状況におかれ、
ようやくCLでそこそこの規模のプログラムを書きました。
*覚えたこと*

(with-open-file
...
:external-format charset:euc-jp)

このように書けば文字コードを指定してファイルを開くことが出来ます。
このサイトなんかが参考になりました。
*勉強の効果(?)*
今まで、なるべく代入を使わないようにして、
再帰を沢山使ってプログラムを書いていたんですが、
今回はsetq, do, do*, dolistを多用しました。
無駄にかっこつけてもしかたないですしね(Lispなのに…)。
doマクロのなかでいくつか変数つくってsetqで代入とかやってたら、
なんだかCのプログラム書いてるのと似たような気分になりました。
そんなプログラム書いてたら、
時折出てくるmapcarが凄くいいものに見えてきました。
やっぱり簡潔に書けるっていい。
しかし、残念だったのが勉強した手のloopマクロを一切使わなかったことです。
やりたいことはdoやdolistで十分できましたし、
そもそもloopマクロで知ってる機能が少なすぎるのかもしれません。
……というか、単にループと代入を沢山使ったプログラムを、
勉強の効果と呼んでいいのやら(笑)
*マクロが便利だけど疲れる*
40行程度のマクロを作ったら、物凄く疲れました。
もっと細かく分割した方がいいのでしょうかね。
まあ、疲れた分、あとでずいぶん楽できたのでよかったです。


*どうでもよくないこと:*
前のエントリーで「ひだまりスケッチ365」とか出力してしまいましたが、
正確なタイトルは「ひだまりスケッチ×365」でした。
正直,スマンかった(AA略

ゆの in ニコスクリプト

金曜日, 7月 11th, 2008

世界中で数人しか知らなさそうですが、
ニコスクリプトは演算子オーバーロードが出来るんですよ!

0::/t=drawText(text:"",size:20,color:0xffffff)
1::/echo=dt
1::/echo.setSlot('lessThan',def_kari('#:g3',t.text+=$1))
2::/trg=dt
2::/trg.setSlot('divide',def_kari('#:g2',t.text+="365";echo))
3::/X=dt
3::/X.setSlot('divide',def_kari('#:g1',t.text="ひだまり"+$1;trg))
4::/_="スケッチ"
5::/X / _ / X < '来週も見てくださいね!'

実行すると動画内時間5秒で「ひだまりスケッチ365来週も見てくださいね!」と画面に表示されます。
dtというのは本来画面に文字を表示する手続き(drawTextの略)ですが、
この手続きは新しい(少し特殊な?)オブジェクトを返します。
で、そのオブジェクトのスロットに'divide'とか'lessThan'といった名前で手続きを格納すると、
'/' や '<' といった演算子が使われたときに任意の手続きが呼べるという仕組みです。 ちなみに、手続きを作るdef_kariは第一引数に名前を要求するので、適当な名前をつけています。 「こうやったら出来るんじゃないか?」と思いつきでやってみたら案外出来るものですね。 ちなみに、ひだまりスケッチはマンガは読んでますがアニメは見てません。
そもそもスケッチブックの方が好きだし。
そんなことよりも問題なのはゆのさまですよ。ゆのさま。
ひだまりスケッチが流行って以来、「ゆのは」でググっても
「'ゆの' は」で引っかかってゆのさまばっかし出てくるんですよ。
もうやってられないんだぜ!
……と書いてから気づいたけど、今はそうでもなくなってるみたいです。
(まあ、やっぱり上位にひだまりスケッチ関連がきてますけど。)
前に検索したときに丁度ひだまりスケッチが流行ってたから上位にきやすかったんでしょうかね。

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

火曜日, 7月 8th, 2008

気が付けばかれこれ2週間もエントリーを投稿していませんでしたが、生きています。
サイクロンゆのはな一号機(自転車)の後輪が壊れて修理に1万円取られたり、
戦国ランスにはまりすぎて廃人になったり色々ありましたが、一応生きています。


「The Common Lisp Cookbook」の「The Loop Macro
を読み終わったので適当にまとめておきます。
*全体として*
説明よりもソースコード嫁!
という感じでした。
冒頭で「最も文書化されていない(least documented)」と書きながら、
ここでも説明が少ないというのには笑いました。
*内容のまとめ*
Loopマクロとは:
– Common Lispの中で最も価値があり、もっとも文書化されていない。
Loopマクロの価値:
(mapや再帰と比べて)
– 強力
– コンパクト
– 読みやすい
Loopマクロを成す4つの部分:
– 変数の設定(これは繰り返される)の式
– 繰り返しを終了させる条件の式
– 繰り返しごとに何かをする式
– 繰り返しを抜ける前に何かをする式
*試してみた*

[21]> (loop for x in '(a b c 1 2 3) thereis (numberp x) do (print x)) A B C T [22]> (loop for x in '(a b c) thereis (numberp x) do (print x)) A B C NIL

thereisは直後に書いた式がnil以外になるとループを抜け、tを返すようです。
全ての繰り返しでnilになれば最終的にnilを返すようです。

[23]> (loop for x in '(a b c 1 2 3) never (numberp x) do (print x)) A B C NIL [24]> (loop for x in '(a b c) never (numberp x) do (print x)) A B C T

neverは直後に書いた式がnil以外になるとループを抜け、nilを返すようです。
全ての繰り返しでnilになれば最終的にtを返すようです。

[19]> (loop for x in '(1 2 3 a b c) always (numberp x) do (print x)) 1 2 3 NIL [20]> (loop for x in '(1 2 3) always (numberp x) do (print x)) 1 2 3 T

alwaysは直後に書いた式がnilになるとループを抜け、nilを返すようです。
全ての繰り返しでnilにならなければ最終的にtを返すようです。
これら3つがwhenとreturnを組み合わせたものというのは大体納得できるのですが、
最終的に返す値を決めるには、これら3つを使わない場合、どうやって指定するんでしょうか。

[31]> (loop for x in '(a b c) never (numberp x) collect x) *** - (LOOP FOR X IN '(A B C) NEVER (NUMBERP X) COLLECT X): ambiguous result: (SYSTEM::LIST-NREVERSE #:ACCULIST-VAR-4350) from COLLECT X T from NEVER (NUMBERP X)

上記の最終的に返す値の話が絡んでいるかは分かりませんが、
never等とcollectを組み合わせるのはまずそうです。

[32]> (loop for x in '(a b c 1) when (numberp x) return x collect x) 1 [33]> (loop for x in '(a b c) when (numberp x) return x collect x) (A B C)

こういう書き方なら問題ないようです。

Common LispとSchemeの多値の違い

月曜日, 6月 23rd, 2008

Common Lispでは多値を必要としない場面で多値(正確には2個以上の値)が返された場合、
最初の値が使用され、後は捨てられます。

(list 1 (values 2 3))
=> (1 2)

ここまでは知っていたんですが、同様に多値を必要としない場面で0個の値が返された場合、
nilが使用されることが仕様で決まっていることを知りました。

(list 1 (values 2 3) (values))
=> (1 2 nil)

なんでもしっかり決まっているのがCommon Lispのいいところですね。
一方、Schemeはどうなっているかというと、
Schemeのvaluesは次のように定義できます。

(define (values . things)
  (call-with-current-continuation
    (lambda (cont)
      (apply cont things))))

つまり、現在の継続に全ての引数を渡すという定義です。
これが正しく動作するには、現在の継続が複数の値を必要としているか(例えばcall-with-values)、
もしくは現在の継続が値を捨てる必要があります(例えばbegin)。
例えば、次のような式を考えて見ます。

(list 1 (values))

R5RSの形式的意味論では、これは「引数の数が異なる」というエラーになります。
R6RSの形式的意味論では、簡約が途中でとまってしまいます。
で、実際のScheme処理系で試したらどうなるか見てみました。
まず、DrScheme

(list 1 (values 2 3))
context expected 1 value, received 2 values: 2 3
> (list 1 (values))
context expected 1 value, received 0 values

R5RSの形式的意味論に忠実な感じです。
次にGauche。

gosh> (list 1 (values 2 3))
(1 2)
gosh> (list 1 (values))
(1 #<undef>)
gosh> (list 1 (values 2 3) (values))
(1 2 2)
gosh> (list 1 (values) (values 2 3) (values) 4 (values) (values 5 6) (values))
(1 #<undef> 2 2 4 2 5 5)

1つ目と2つ目を見た段階では、Common Lispとほぼ同じ仕様かと思いきや、
3つ目と4つ目がなんだか凄いことになってます。
これはバグ……というか仕様でしょうか。

第4回 慢性的CL勉強会[まとめ]

日曜日, 6月 22nd, 2008

Lingrのログはこちら
*疑問への回答*
今回もまた質問に答えていただきました。
いつも本当にありがとうございます。
– carを書き換えるnreverse
リストの要素の方を入れ替えれば可能。
HyperSpecにもcar/cdrのどちらを書き換えても良いと書いてあるそうです。

(format t "Test ~A ~:[FAILED~;passed~].~%"
',name (progn ,@body))

(format t ~:[にる~;てー~]~%” t) ;=> てー
(format t ~:[にる~;てー~]~%” nil) ;=> にる
だそうです。

,@(when condition
`((,condition () (format t "Test ~A passed.~%"
',name))))

,@ を , に変更して、 ((,condition …)) を (,condition …) に変更すると、
conditionがnilであるとき、この式全体がnilとして残ってしまいます。
@nilを使えば、@,nilとなってnilが消えるという仕組みです。
これはwhenの条件部がnilのときの値はnilになるということに基づいていますが、
whenの戻り値を使うべきではないという宗派もあるため、
ifやandを使うべきという意見もあるようです。
ちなみにschemeのwhenは条件部が偽のときの値は未定義だとか。
今回は勉強会後の雑談コーナーが一番熱かった気がします(笑)
*がんばって自分で調べてみた*
自分で投げかけた疑問を放置しておくのもどうかと思うので、
一部だけですが自分で調べてみました。
以下の内容は全てCLtL2日本語版を参考にしています。
– read-from-string
文字列を与え、それをリーダによってLispオブジェクトに組み立てて返す関数。
読み込まれなかった文字列の中の最初の添え字も返すとのこと。
– potential number(潜在的な数)
数の構文の拡張を可能にするために定義された構文。
潜在的な数であり、なおかつ実際の数の構文に合わないようなトークンは、
すべて予約語となり、処理系に依存した解釈となるそうです。
処理系はエラーを発しても良いし、シンボルとしてトークンを扱っても良いし、
あるいは何か他の行動をとっても良いとか。
まあ、使わない方が無難なようです。
– proclaim
宣言の効果をグローバルに持たす「関数」。
(proclaim ‘(type float tolerance))
を評価すると、toleranceの動的な値は常に浮動小数点数となるべきことを指定するそうです。
関数であるため、コンパイル時に効力を期待するなら、
eval-whenで囲むか、declaimを使うべきだとか。
– declaim
proclaimと同様のことを行う「マクロ」。引数は評価されない。
コンパイル時に宣言がなされることになるそうです。

毎週、何かしらの資料を読んで、
おまけに疑問に対する回答まで頂いてるため、
ここ数週間でかなりCLに対する知識が増えた気がします。
ただ、短いサンプルソースといったようなものしか読んでいないため、
本当にCLを使えるようになるためには、もっと実践的なソースを読んだり、
なにかモノを作ったりする必要がありそうです。
早くCLerになりたい!!

おまけ

# onjo
# いやいやよく考えてください、 ((((foo)))) こんな呼び出し嬉しくない。
# (funcall (funcall (funcall (funcall foo)))) 何回呼んだかすぐわかる。カッコの数を数えるなんて苦痛。

いやいやよく考えてください、
(funcall (funcall (funcall (funcall ;゚Д゚))))
こんな呼び出し嬉しくない。
(((( ;゚Д゚))))
顔文字であることがすぐに分かる。崩れた顔文字は苦痛。
なんてことを考えてしまったwww