ecl (6)

WindowsME時代のノーパソに色々なOSを入れて楽しみ、余生はFreeBSD6.4になってる。 NICは、昔に買ったバファローの親子無線機の子機を利用してる。

ノーパソは内蔵のNICが壊れ、やむなく蟹さんチップを内臓したPCMCIAなカードを使って たんだけど、別用途で使ってた親子無線機の親が逝っちゃったものだから、子はしばし 休眠。

引越しを期にISPが変わって、加入祝いに無線LAN(親)を貰ったので、子を引っ張り出して きて、BSDと合体させて使ってた。所が、最近になって使用途中に無線が切れて、ping 不導通となる事態が発生。

この症状が段々と顕著に現れるようになり、最後はBSD起動直後から、NICのstatusが キャリアー無しとなってしまった。こんな状態じゃ、dhclinetしても、no link と言われて 通信が確立しない。

はて、どこが悪いのでしょうか? 研修医の諸君、自分の見立てを述べよ。って、TV番組で やってたよ。新人研修医は、しばしば見立てを誤り、恐い存在だな。

おいらの見立てだと、無線カードの高周波アナログ部PHYが昇天したと思われる。 他の無線受信器で帯域をモニターすると、ちゃんと波が出てましたから。

これで死亡確定。後日解剖予定です。痛いはバフアローに返却ですかね。生みの親に 返すのが一番だと思うんだ。

で、WindowsME上がりのPCは、HDDが頑丈な為(富士通のHDD部門を褒めてあげたい。あれ、 あそこは撤退したんかな)まだまだ余生を送れますよ。たまに蟹さんチップのNICを刺して 世間の風を送り込んであげる事にします。

それにしても、おいらはNICと相性が悪いな。

今回の読書メータ 7冊 / 2174頁 / 13650円

Gauche profiler

孤独なFreeBSD6.4マシン(線を繋げば、世間と繋がるけど、配線すんの面倒)、一人でも 楽しめるようにしとくか。色々なAppをソースから入れて、後はgdbあたりを使って観察 するなんて、世間に背を向けた、引きこもりにはぴったり。

入ってるGaucheのVerが古いしソースも無かったので、新しいのを入れておくか。 コンパイルを始めたのはいいんだけど、system.cの2203行目でエラーになった。 システムコールしてる行。

void Scm_UnsetEnv(const char *name)
{
#if defined(HAVE_UNSETENV)
    int r = 0;
    SCM_SYSCALL(r, unsetenv(name));
    if (r < 0) Scm_SysError("unsetenv failed on %s", name);
#else  /*!HAVE_UNSETENV*/
    Scm_Error("sys-unsetenv is not supported on this platform.");
#endif /*!HAVE_UNSETENV*/
}

unsetenvはconfigで検出したものの、I/Fが合わなくてエラーなんだろうな。 それ以上の追求は止めて、UNSETENVなんて無い事にしちゃったぞ。(src/gauche/config.h) これで、コンパイル完了。

早速、gdbでstep実行してったら

      /* Set up instruments. */
  =>  if (profiling_mode) {
          if (Scm_Require(SCM_MAKE_STR("gauche/vm/profiler"), 0, &lpak) < 0) {
              error_exit(lpak.exception);
          }
          Scm_ProfilerStart();

main関数の中で、プロファイルを起動してる部分に出会った。最近はprofileに縁が有る なあ。きっと、もっとprofileを調べて見ろって事だな。

Gauche:VMの最適化:For 0.8.4 で入ったProfileが出てきた。楽しい使い方の例が載ってた。 Gauche:プロファイラAPIの使用例 そして、profileがマクロで出来ちゃうという素晴らしい試み。 プロファイラ

Scm_ProfilerStart()が何処に有るかと思ったら、prof.cだった。収録データが大量に成りそうなので、 /tmp/gauche-profXXXXXX に書き出す仕様かな。準備が整ったら、タイマーにスタートを かけているんだな。

    act.sa_handler = sampler_sample;
    sigfillset(&act.sa_mask);
    act.sa_flags = SA_RESTART;
    if (sigaction(SIGPROF, &act, NULL) < 0) {
        Scm_SysError("sigaction failed");
    }

    ITIMER_START();

これ、Scm_ProfilerStart()を抜ける直前部分。sigactionで、sampler_sampleという ハンドラーを登録してる。なお、 シグナルに関するややこしい話 が載ってる所を見つけたので、メモしとく。

タイマーは、周期 10000マイクロ秒毎にSIGPROFが発生するように設定してる。 そのためのsetttimerなんてサービスがUnix用に提供されてた。Windows用は知らん。

核になるのは、sampler_sample(int sig)の

    i = vm->prof->currentSample++;
    if (vm->base) {
        /* If vm->pc is RET and val0 is a subr, it is pretty likely that
           we're actually executing that subr. */
        if (vm->pc && SCM_VM_INSN_CODE(*vm->pc) == SCM_VM_RET
            && SCM_SUBRP(vm->val0)) {
            vm->prof->samples[i].func = vm->val0;
            vm->prof->samples[i].pc = NULL;
        } else {
            vm->prof->samples[i].func = SCM_OBJ(vm->base);
            vm->prof->samples[i].pc = vm->pc;
        }
    } else {
        vm->prof->samples[i].func = SCM_FALSE;
        vm->prof->samples[i].pc = NULL;
    }
    vm->prof->totalSamples++;

VMの内部状態をアクセス出来れば、継続とか言わなくていいんだ。自前の仮想PCの 有り難さがよく分かりますよ。

profileって、計算量も測れるんだけど、それをグラフにするなんてのを見つけた。 グラフを書くのはgnuplot。

(define (plot d)
  (display "plot '-' w l\n")
  (force d)
  (display "end\n"))

(define (fib n)
  (define (iter a b count)
    (display (format "~a ~a\n" count b))
    (if (= count n)
        b
        (iter (+ a b) a (+ count 1))))
  (iter 1 0 0))

(plot (delay (fib 20)))

使い方は、次のようにする。

sakae@uB:~/src$ gosh plot.scm | gnuplot -persist

勝手に折れ線グラフを描いた窓が出てくるよ。

もう少しECL

LispはFortranと並んで今や古の言語になってしまった。Lispの考え方はPerlやらPythonやら Rubyに移植されている。rubyなんてmatzさんが作ったlispと言われるぐらいだから。

でも、決定的に移植されていない機能がある。それはMACRO。matzさんのマクロ嫌いは 有名だけど、それでもDSLでその片鱗を見せているな。

よって、Lispを勉強するならMACROをやっておかないと片手落ち。On Lispをちまちまと 読んでいる。読み終わったらLoLに行く予定。LoLは口の悪い人に言わせると、Lispの同人誌 らしいですが。

On Lispの中に、マクロを展開して綺麗に表示してくれるマクロが潜んでいる。

CL-USER> (defmacro mac (expr)
             `(pprint (macroexpand-1 ',expr)))
MAC
CL-USER> (mac (mac mac))

(PPRINT (MACROEXPAND-1 'MAC))
; No value

使い方の例を載せたけど、最悪の例だな。オイラーは決して某ハンバーガー屋の回し者 でも、アプルの回し者でも ありません。最初のmacは、今定義したmacの呼び出し、次のマックは展開したいマクロ名、 最後は、その引数。

もう少し、実用的な例。profile.lispの中に、dohashって言うマクロが有る。

  (defmacro dohash (((key value) hash &key locked) &body body)
    (let* ((it (gensym))
           (entry (gensym))
           (body
            `(with-hash-table-iterator (,it ,hash)
               (loop (multiple-value-bind (,entry ,key ,value)
                         (,it)
                       (unless ,entry (return))
                       (let ()
                         ,@body))))))
      (if locked
          `(mp:with-lock (*profile-lock*) ,body)
          body)))

(defun reset ()
  "Reset the counters for all profiled functions."
  (dohash ((name profile-info) *profiled-fun-name->info* :locked t)
    (declare (ignore name))
    (funcall (profile-info-clear-stats-fun profile-info))))

hashにアクセスする時にロックをかけてから行うので、それを簡便に書けるようにしたんだ。 定義したマクロは使ってナンボ。早速、リセットの中で使ってる。これが、どう展開されるか?

CL-USER> (mac (dohash ((name profile-info) *profiled-fun-name->info* :locked t)
                          (declare (ignore name))
                              (funcall (profile-info-clear-stats-fun profile-info))))

(MP:WITH-LOCK (*PROFILE-LOCK*)
              (WITH-HASH-TABLE-ITERATOR (#:G184 *PROFILED-FUN-NAME->INFO*)
                (LOOP
                 (MULTIPLE-VALUE-BIND
                     (#:G185 NAME PROFILE-INFO)
                     (#:G184)
                   (UNLESS #:G185 (RETURN))
                   (LET ()
                     (DECLARE (IGNORE NAME))
                     (FUNCALL (PROFILE-INFO-CLEAR-STATS-FUN PROFILE-INFO)))))))
; No value

slimeを起動してるなら、マクロの定義を、C-x C-e で評価(登録)した後、使ってるマクロの左括弧の上で、 C-c C-m で、同じ事が出来るぞ。

On Lispを読んでいると、さかんにCLt2って言葉が出てくる。これは何ってんで調べて みたら、CLが委員会に承認されてISOになる前に、叩き台として出版されたドラフト。 あの有名な方が執筆してる。

日本でも出版されてて、某所で見せてもらったけど、電話帳より熱かったですよ。厚い んじゃなくて、陽のように熱かったって事です。今は、 Common Lisp the Language, 2nd Edition で公開される。

Arc

Lisp系の紹介シリーズ、今回は、昔を思い出して、 Arcです。勿論、あのポールさんの策。 一時注目を集めていて、 Arcをリリースした なんて、翻訳をされた方が居ました。

取ってきて実行してみようとしたら、

1. Install version 372 of MzScheme. (Don't use the latest version. Versions after 372 made lists immutable.)
2. Get http://ycombinator.com/arc/arc3.tar and untar it.
3. Type mzscheme -m -f as.scm and you should get an Arc prompt.
4. If you ^C an Arc program, you'll get the Scheme REPL. Use (tl) to get back to the Arc REPL.
5. If you have questions or suggestions, post them on the forum. 

MzSchemeのバージョンまで指定してますよ。しょがない入れてみるかってんで、

sakae@uB:~$ mzscheme
The program 'mzscheme' is currently not installed. You can install it by typing:
sudo apt-get install racket

plt-schemeって名前のやつにCUI版としてmzschemeが付いていたはずなんだけど、ラケットに に名前を変えてるんだ。入れるの諦めましょ。ソースだけでも拝んでみるか。

arc0.tarが初期バージョンなので、コードも小さかろう。

sakae@uB:~/src/arc0$ cat as.scm
; mzscheme -m -f as.scm
; (tl)
; (asv)
; http://localhost:8080

(require mzscheme) ; promise we won't redefine mzscheme bindings

(load "ac.scm")
(require "brackets.scm")
(use-bracket-readtable)

(aload "arc.arc")
(aload "libs.arc")

(tl)

ポールが設計した変換器がac.scmに書かれているんだな。そいつをロードして、mzscheme 雰囲気からポールの雰囲気に変えておく。後は、ポール語で書かれた、ファイルをロード して使うとな。arc.arcあたりを見ると、間接的のポール脳に触れられるって訳だな。 よし、触ってみよう。goshに移植出来るか?

sakae@uB:~/src/arc0$ gosh ac.scm
gosh: "error": Compile Error: require: string expected, but got (lib "port.ss")
"./ac.scm":45:(module ac mzscheme (provide (all-de ...

sakae@uB:~/src/arc0$ gosh ac.scm
gosh: "error": unbound variable: namespace-set-variable-value!

当たり前だけど、エラーになる。そこで、冒頭付近にある方言を強引に削除して実行。 hashの検索方法がおかしいってエラーを乗り越えて、たどり着いた所が上記のエラー。

namespace-set-variable-value って、CLで言う所のパッケージなのかな。RnRSに強引に突っ込もうとして、他の陣営の 顰蹙を買ったとか、いわく付きのもの? でもracketには、plot とかのライブラリーも用意されてて、嬉しいのはいいんだけど、オイラー的には、 何となくM$のWordあたりを連想しちゃって、近寄りがたいな。

schemeでグラフィックしたいなら、 Schluessel - A Scheme Implementation on Java - が有ります。素のWindowsでも動くので、いい鴨。

schemeはミニマム主義をずっと貫いて欲しいものです。

Build Your Own Lisp

Arcはばっさりと諦め、他に面白そうなのが無いかと探してみた。出てきたのは、 Build Your Own Lispですって。 自分で組み立てろとな。こちらなら、ドイトかな。都心方面ならイケアか。

キットが有ったので、取り寄せて組み立ててみた。少しづつ組み立てて行くのね。

sakae@uB:~/src/yol$ grep Version *.c
conditionals.c:  puts("Lispy Version 0.0.0.0.9");
error_handling.c:  puts("Lispy Version 0.0.0.0.4");
evaluation.c:  puts("Lispy Version 0.0.0.0.3");
functions.c:  puts("Lispy Version 0.0.0.0.8");
parsing.c:  puts("Lispy Version 0.0.0.0.2");
prompt_unix.c:  puts("Lispy Version 0.0.0.0.1");
q_expressions.c:  puts("Lispy Version 0.0.0.0.6");
s_expressions.c:  puts("Lispy Version 0.0.0.0.5");
strings.c:    puts("Lispy Version 0.0.0.1.0");
variables.c:  puts("Lispy Version 0.0.0.0.7");

最後のバージョンのものを走らせてみる。

sakae@uB:~/src/yol$ wc strings.c
  913  2934 24342 strings.c
sakae@uB:~/src/yol$ ./strings
Lispy Version 0.0.0.1.0
Press Ctrl+c to Exit

lispy> (+ 1 2)
3

ちゃんとLispしてますよ。1000行に満たないサイズです。コードを読むには手頃な 分量かな。ちら見して、なんとなく

lispy> (if (== 3 4) (print "Same")(print "Not same"))
"Same"
"Not same"
Error: Function 'if' passed incorrect type for argument 1. Got S-Expression, Expected Q-Expression.
lispy> (if (== 3 4) {(print "Same")} {(print "Not same")})
"Not same"
()

ライブラリィーに leditが付いていて、行編集でけた。{} で、囲むとデータに なるのかな。tの代わりが1、nilの代わりが0になってた。

lispy> def {add1} (\ {n} {+ n 1})
()
lispy> add1 4
5

一番外側の括弧は書かないみたい。そして、defunの代わりが、defで、バックスラシュが lambda式を表すようだ。matzさんもびっくりの言語デザインですよ。

ですから、日経Linuxの かの人の連載も良いけど、こちらも見てね。パアスは他人任せしてて、ずるいと思う半面、 決まりきった事だからrubyみたいな技巧的構文でない限り、これでいいんだとも思うぞ。

PowerShell ISE

前回だったか、Windowsのshell環境を貶したけど、IDEな環境が用意されてるのね。 知らんかったぞ。気が向いたら使ってみよう。

統合開発環境「PowerShell ISE」を使ってみよう

万次郎のカーネル

って、特殊なコマンドを使わないと上げられのね。知らんかった。

Manjaro Kernels