AM-Scheme(4)
昨日は、shibuya.lisp#4 へ行ってきた。近山先生のUtiLispの話、竹内先生のVax-11改造の話 面白かったよ。ICの上にICを乗っける、小亀方式って、だれでも考えつくよね。おいらも、昔 よくやったものです。
先生は、NANDゲートの事をおっぱいゲートと言ってらっしゃったけど、NANDよりもNORの方が 張りがあって、おいらはこっちの方が好きです。いわゆるロケット型おっぱいですね。って、 一体、何を聞いてきたんだろう。でも、先生の著著にサインも頂いた事だし、もう一度読み 直してみるかなあ。
夜の宴会は、若い人の前で、CERNのWeb serverがどうのとか、モザイクがどうのとか、爺の 馬鹿話をしてしまい失礼しました。
Lispが分かれば無敵さん、寿限無さん お世話になりました。
gdbとemacsの連携
近頃(でもないかな)は、emacs上でdebuggerを使う場合、debuggerへのインターフェースが 統一的に扱えるよう、gudという仕組みが搭載されてるようだ。C-h b を使って、gdbのキーバインド を調べてみたよ。
C-x SPC gud-break C-x C-a C-b gud-break C-x C-a C-d gud-remove C-x C-a C-f gud-finish C-x C-a TAB gud-stepi C-x C-a C-j gud-jump C-x C-a C-l gud-refresh C-x C-a C-n gud-next C-x C-a C-p gud-print C-x C-a C-r gud-cont C-x C-a C-s gud-step C-x C-a C-t gud-tbreak C-x C-a C-u gud-until C-x C-a C-v gud-pv C-x C-a C-w gud-watch C-x C-a < gud-up C-x C-a > gud-down
一人でgit
生鮮食料品である、今月号のSDを見ていたら、gitの使い方が出ていた。昔はCVSっつう事 で、ちょっとやった事があるけど、svnをすっ飛ばして今はgitだ。時流に乗り遅れない ようにやってみるか。記事を要約すると
cd work vi .gitignore git init git add . git commit -a -m "original" git tag 0.0 vi xx.c git commit xx.c -m "message" git tag X.X
git管理したいwork-dirに移動。gitに加えたく無いファイル類(例 *.o等)を列挙した .gitignore を作成。続いて、initで、倉庫を作り、add . で、登録したいファイルを 選定。続いて、commitで、登録。ついでにtagを打っておく。ここまでは、初回のみ 一回だけ行なう。
修正を加えたら、適当な所で、commitし、ある程度まとまったら、tagを更新していく。 この繰返しを続ける。
Real World Haskellの現場からAM-Schemeに移植
献本頂いたRWHを最初から丁寧に読んでいる。そしたら、ghcには、唯一の定数として piがあるそうな。他によく使う定数として e があるけど、ghc にはあらかじめ定義して ないとの事。現場で作るらしい。
Prelude> pi 3.141592653589793 Prelude> e <interactive>:1:0: Not in scope: `e' Prelude> let e = exp 1 Prelude> e 2.718281828459045
勿論、これはHaskellの考え方であって、利のきいたschemeでは、最初から、両定数は 定義されてる事が多い。今やってるAM-Schemeはどうかというと、軽量を旨としてるので 勿論そんなサービスは無い。無かったら付け足すだけ。取り敢えず、tools.scmにでも 潜りこませておけばいいだろう。潜りこませた結果は、
commit 980dbba57b988bf0be3e8dc0dde5084e31e77197 Author: Sakae Kobayashi <sakae@fb.kuma.net> Date: Fri Nov 6 16:45:31 2009 +0900 Add constant pi,e diff --git a/tools.scm b/tools.scm index 45212bd..b5aa0d8 100644 --- a/tools.scm +++ b/tools.scm @@ -472,3 +472,6 @@ (ed-list lis level)))) (ed-list lis 0))) +;;; some constant +(define pi 3.141592653589793) +(define e (exp 1))
こんな感じになった。 実行してみると、
> pi 3.14159 > e 2.71828
あれ? 折角、精度よく設定したのに、下5桁しか表示してくれないね。勿体ない事です。
> 1234567890.123456 1.23457e+09
大きな数字は、E表現にしてくれちゃうのね。多分、浮動小数点な数は、自動表現になってると思うので、探して書き換えちゃえ。
[sakae@fb ~/v110/src]$ git diff diff --git a/print.c b/print.c index 8b65045..4dd3914 100644 --- a/print.c +++ b/print.c @@ -68,7 +68,7 @@ int pr; } else if (isinteger(l)) { length = printinteger(l, file, pr); } else if (isreal(l)) { - sprintf(&strbuff[0], "%g", rvalue(l)); + sprintf(&strbuff[0], "%-20.6f", rvalue(l)); length = strlen(&strbuff[0]); if (pr) PrintString(file, &strbuff[0]); } else if (isstring(l)) {
後は、commitしておこう。commitしちゃうと、見えなくなっちゃうんだよなあ。
AM-Schemeに手続きを追加しる
さてはて、折角ここまできたので、AM-Schemeに手続きを追加して、俺様Schemeに してみよう。で、10秒考えて、timeを実現するためのプリミティブを追加する。
ANSIでは、廃止の方向で動いている(代わりに、clock_gettime(2) が推奨されているとか) gettimeofday() を使って、EPOC を、マイクロ秒 まで求めてみる。 手続き名は、安直に、gtod とでもしよう。
diff --git a/init.c b/init.c index f7900f3..2927be9 100644 --- a/init.c +++ b/init.c @@ -286,6 +286,7 @@ init_globals() mk_prim2(PR_UNBOX, "unbox", MUST_BE_N(1)); mk_prim2(PR_SETBOX, "set-box!", MUST_BE_N(2)); mk_prim2(PR_EXIT, "exit", MUST_BE_N(0)); + mk_prim2(PR_GTOD, "gtod", MUST_BE_N(0)); // gettimeofday /* intialization of global pointers to special symbols */ LAMBDA = mk_sym_from_cstr("lambda", STDCHARCASE); diff --git a/prim.c b/prim.c index 3daed4c..3fed7cf 100644 --- a/prim.c +++ b/prim.c @@ -10,6 +10,8 @@ */ #include "amscm.h" +#include <time.h> // For gettimeofday +#include <sys/time.h> // dito extern int UpperCase(); extern int LowerCase(); @@ -1171,3 +1173,12 @@ pointer PR_EXIT() /* exit */ /* Added by Akira Kida */ { longjmp(reset_jmp, 2); } + +// Add by sakae gtod -- gettimeofday +pointer PR_GTOD() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return mk_real(tv.tv_sec + (double)tv.tv_usec*1e-6); +} + diff --git a/prim.h b/prim.h index 1eae4ed..85a4aa2 100644 --- a/prim.h +++ b/prim.h @@ -151,3 +151,4 @@ extern pointer PR_BOXP(); extern pointer PR_UNBOX(); extern pointer PR_SETBOX(); extern pointer PR_EXIT(); +extern pointer PR_GTOD();
init.c に手続き名を登録し、同様にprim.h にも登録。prim.c の頭(でいいのか?)に gettimeofday を使う時の ヘッダーファイルを指定。ファイルの最後に、実体を追加した。
> (gtod) 1257504944.097936 > (let ((st (gtod))) (load "tools.scm") (- (gtod) st)) ;loading tools.scm : pi e 0.004829
gtodをそのまま使うと、EPOC秒を返す。(let .. (xxx) ...) のようにすると、(xxx)の 実行時間(上記では、load手続き)を、計測できる。結果は、4.8ms となった。
マクロでも、、
gtodで、時間が取れるようになったので、S式の実行時間計測用のコードを書いてみよう。 (time hoge) で、hogeの実行時間を計るようにするわけだが、hogeを評価してからという訳には いかない。こういう時はマクロの出番だ。上記の(let ...)のようにして、hogeを挟みこむ。
> (macro time (lambda (body) `(let ((st (gtod))) ,body (- (gtod) st)))) time > (time (fib 10)) Error: Unbound variable f [return to toplevel]
上記のマクロで良いはずなんだけど、何故か動かない。展開がうまくいかないのかな? bodyを定義しておいてから、手動で展開して、それを実行してみる。
> (define body '(fib 10)) body > `(let ((st (gtod))) ,body (- (gtod) st)) (let ((st (gtod))) (fib 10) (- (gtod) st)) > (let ((st (gtod))) (fib 10) (- (gtod) st)) 0.002304
これでは、うまくいっているな。何故だめなんだろう? 後で潜ってみるか。