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
これでは、うまくいっているな。何故だめなんだろう? 後で潜ってみるか。