emacs buffer
Table of Contents
benchmark-run
前回、ベンチマークなんてのが用意されてるのを知ったものだから、試してみ る(gaucheならtimeなんだけどね)。試験台は、迷路を作成する関数(から、結果の表示をしないようにしたも の)。
ELISP> (benchmark-run (generate 10 30)) (0.078006929 0 0.0) ELISP> (benchmark-run 10 (generate 10 30)) (0.863384621 1 0.045810978)
実行時間、GCの回数、GCの時間ってとこかな。早起きは三文の得に習って、ソー スに対面しとく。これぞOSSの最大の楽しみだからね。
(defmacro benchmark-run (&optional repetitions &rest forms) "Time execution of FORMS. If REPETITIONS is supplied as a number, run FORMS that many times, accounting for the overhead of the resulting loop. Otherwise run FORMS once. Return a list of the total elapsed time for execution, the number of garbage collections that ran, and the time taken by garbage collection. See also `benchmark-run-compiled'." (declare (indent 1) (debug t)) (unless (or (natnump repetitions) (and repetitions (symbolp repetitions))) (setq forms (cons repetitions forms) repetitions 1)) `(benchmark-call (lambda () ,@forms) ,repetitions))
マクロ仕様の関数になってる。して、その核心は、
(defmacro benchmark-elapse (&rest forms) "Return the time in seconds elapsed for execution of FORMS." (declare (indent 0) (debug t)) (let ((t1 (make-symbol "t1"))) `(let ((,t1 (current-time))) ,@forms (float-time (time-since ,t1)))))
時間計測の方法が分ったぞ。実際に分解してやってみる。
ELISP> (defvar t1 (current-time)) t1 ELISP> (float-time (time-since t1)) 9.40873745 ELISP> t1 (25879 21730 73284 817000)
current-timeで現在時刻を記憶。time-sinceで、そこから(t1)の時間差を算出。 後は、それを人間様用に変換してるんだな。
やや、ただのbenchmarkってのも有るな。こちらは、ただの関数だ。
ELISP> (benchmark 20 (generate 10 30)) "Elapsed time: 0.000004s" ELISP> (benchmark 20 '(generate 10 30)) "Elapsed time: 1.701876s (0.046847s in 1 GCs)"
だから評価したい関数には、先頭に ' を付けて、データだから、ここでは評価しないで ねって指示が必要。
ついでなので、current-timeの源流まで、遡ってみる。
make_lisp_time (struct timespec t) { if (CURRENT_TIME_LIST) { time_t s = t.tv_sec; int ns = t.tv_nsec; return list4 (hi_time (s), lo_time (s), make_fixnum (ns / 1000), make_fixnum (ns % 1000 * 1000)); }
t.tv_sec
が2つに分解されてるのは、整数のビット数が、30ビットのマシ
ンを救済するためみたいだ。おかげで貧乏人でも快適にemacsを利用できる。
どこかのリナとかパイソンみたいに、切り捨てはしないのさ。
まだ上流が有るけど、これぐらいにしておく。1970-01-01 00:00:00 からの経 過時間って事で、察してください。
with buffer
前回からの宿題、迷路を作成して探索経路も一遍に表示したい。普通に考えた ら、スクリプトにしちゃえば良いはずだけど、それじゃ負けた気分。 で、emacsのバッファーとやらの登場。
editorである限りファイルを編集できなければならない。それには、ファイル の内容を一旦メモリーに読み込んでとなる。そのメモリーの事をバッファーと 呼んでいる。
下記の簡単なバッファーの使用例をあげる。
;; test-bufferという名前のバッファを作成し、いろいろな内容を書き出す (with-current-buffer (get-buffer-create "test-buffer") ;; バッファの内容を空にする (erase-buffer) ;; /tmp/foo.txtの内容を挿入する (insert-file-contents "/tmp/foo.txt") ;; 文字列を挿入する (insert "End\n") ;; バッファの内容をファイルに書き出す (write-region (point-min) (point-max) "/tmp/bar.txt"))
で、出来たのが下記。バッファーを作成して、その中にprint-maze似のpmb関 数を利用して出力。後はそのバッファーをLOGファイルに書き出す。一番簡単な奴 だな。
(defun qa () (setq maze (new-maze 12 30)) (dig-maze maze 1 1) (with-current-buffer (get-buffer-create "test-buffer") (erase-buffer) (pmb maze) (write-region (point-min) (point-max) "/tmp/LOG")) (testr) (print-maze rmaze res) )
肝心のpmb関数だけど、princをinsertに変更。terpriはnewlineに変更したも のだ。いわゆるlisp系の出力と、emacsのbuffer系の出力では、系統が違うの ね。間を取り持つ何かが有ってもよさそうだけど、今の所探し当てられていな い。果して、そんなのあるんか?
同じロジックで中身がちょっと違うってのは、まずい。非常にまずい。Railsの人達か ら、ヤーイ、DRYの原則に違反してるって指摘されるぞ。さて、どうする? マクロの出番かな? まて、マクロは安易に使うな、と、マクロの指南書 On Lispに書いてあったぞ。
print-maze と pmb の 融合
マクロを使わないで、2つの関数を融合せよ。散歩してたらアイデアが閃いた。 切り替え用の引数を追加する。文字列を直接出力すんじゃなくて、一旦、文字 列に貯めると言う方法。そして、改行の場面で、出力先を振り分け。
format
まずは振り分けの手法。formatなんてのを思い出した。ちょいとsbclで確認。
* (format t "hello") hello NIL * (format nil "hello") "hello"
おまけで、gaucheでも確認。
gosh$ (format #t "hello") hello#<undef> gosh$ (format #f "hello") "hello"
formatの主目的は、printfのように、自在にフォーマッティグする事なんだけ ど、第一引数により、結果を端末に送るか、文字列にするか指定できるんだ。
なおemacsにも同名の関数が用意されてるけど、切り替え機能は無い。 4.7 Formatting Strings on emacs
文字列の連結
探し方が悪いのか、特別な関数は用意されてないっぽいんで、下記で我慢かな。
ELISP> (defvar s "") s ELISP> (setq s (concat s "hello ")) "hello " ELISP> (setq s (concat s "world.")) "hello world."
ついでに、関数定義も
ELISP> ((lambda (x) (princ x)(terpri)) s) hello world. t
join print-maze and pmb
融合させてみた。
(defun pmb (term maze &optional marks) ; if term is nil then output to buffer (defun toterm (s) (princ s) (terpri)) (defun tobuf (s) (insert s) (newline)) (let (s) (dotimes (r (1- (maze-rows maze))) (setq s "") (dotimes (c (1- (maze-cols maze))) (setq s (concat s (if (maze-is-set maze r c 'ceiling) "+---" "+ ")))) (setq s (concat s "+")) (if term (toterm s) (tobuf s)) (setq s "") (dotimes (c (1- (maze-cols maze))) (setq s (concat s (if (maze-is-set maze r c 'wall) "|" " "))) (setq s (concat s (if (member (cons r c) marks) " * " " ")))) (setq s (concat s "|")) (if term (toterm s) (tobuf s))) (setq s "") (dotimes (c (1- (maze-cols maze))) (setq s (concat s (if (maze-is-set maze (1- (maze-rows maze)) c 'ceiling) "+---" "+ ")))) (setq s (concat s "+")) (if term (toterm s) (tobuf s))))
let節の中に、totermとかを突っ込みたかったけど、それは許されなかった。
実行例
ELISP> (qa 2 3) + +---+---+ | * * | + + +---+ | | * * | +---+---+ + ELISP> (qa 3 10) + +---+---+---+---+---+---+---+---+---+ | * | | | | | * * | + + + +---+---+ +---+ + + + | * * | | | * | * | + + +---+ +---+ +---+---+ + + | | * * * * * * * * | * | +---+---+---+---+---+---+---+---+---+ +
今迄のように、LOGファイルに記録しなくても、さっと、問い合わせと結果が 表示出来るようになった。
macro
上記を書いている時、面倒だなあ。間違いそうと想った。 そう、文字列を集積してく部分ね。案の定、括弧の書き間違いで、酷いエラー を誘発した。ならば、マクロか。まて、それは最後の手段。
今回に限れば、これで行けるはず。この定義を利用すれば、princをscに書き 換えするだけで済む。間違えようが無い。
(defun sc (v) (setq s (concat s v)))
これに汎用性を持たせるとしたら、そうはいかなくなる。蓄積変数 s が決め 打ちになってるからね。どうしてもマクロの出番。
(defmacro sc (n v) `(setq ,n (concat ,n ,v)))
バッククォートの内側で、冒頭にカンマを付けると、その部分が展開される。
ELISP> (macroexpand '(sc name val)) (setq name (concat name val))
こんな風に展開された。指示したS式から、新たな式を作成、それが実行され るんだ。
ELISP> (defvar aa "") aa ELISP> (sc aa "hello") "hello" ELISP> (sc aa "-world") "hello-world" ELISP> aa "hello-world" ELISP> (defvar z "") z ELISP> (sc z "I am ") "I am " ELISP> (sc z "macro") "I am macro" ELISP> z "I am macro"
commonLisp/elispのマクロは注意して作成しないと、名前衝突とかのややこし い問題が生じる。だから、On LispだとかLET OVER LAMBDAなんて言う指南本が 出版されるのな。
それに対してschemeは、違ったプローチでマクロを実現してる。そのあたりの 喧喧諤諤なやりとりが、 マクロとか に有る。懐しいな。おっ、 黒田節。
networkx and …
たまには、本屋で情報収集と言う立ち読みを実施。流行はやはり、生成AIだ。 日経リナとかソフトウェアは言うに及ばず、インターフェース誌も大特集を組 んでいた。CQ誌でさえも、アマチュア無線の未来を占ってもらっていたぞ。
そんな中で、networkXを使って、ネットワーク図を書きましょうと言うのが目 にとまった。頭の中から溢れ落ちないように、そーと家に持ち帰り。
pipで入れるのは、お約束なんだけど、色々と連鎖してないか?
PiPy networkX して、そこから、source codeをクリック。githubに行きつく。 これって、単一故障点。怖い世の中だのう。
networkx/pyproject.toml これがインストール仕様書なのかなあ。なんか、関 連品が沢山列挙されてるんだけど。。。
とりあえず入れた。単独ではいった。カジュアルには、描画にmatplotlibを使 うみたいだけど、先客で用意されてたので、追加は無かったのかな。
解説ページを検索。割とポピュラーなのね。知らない事ばかり。
Software for Complex Networks Tutorial
応用として、どんなものが考えられるのだろう? 例では最短経路の探索。 カーナビに搭載されてる? 駅スパートにも入ってるかな。 プロバイダーな人なら、ネットワークのパケットを何処に流したら得かのシュ ミレーションに利用できそう。まて、そんなのコミコミでBGPだかに組み込ま れているか。
更に近傍を探ってみると、 Welcome to nx-guides! こんなのが出てきた。数独の解法に役だちます。フェースブックで、繋りの分 析もできます。世界は6ホップだかで、繋っているというあれだな。オイラー の所から、バイデン閣下まで、6ホップで届くのか。多分、あの人に連絡すれ ば、あの人が米国の誰かを紹介してくれるだろう。2ホップで米国まで到達。 たまには、あの人にpingしてみるかな。
あと、大事な応用を忘れていた。ググるのページランクね。一杯リンクが貼ら れているページは重要なサイトだろうっていうやつ。ノードに繋るエッジ数そ のものじゃん。ググルの開発者は、これに目をつけたんだな。
例によってgithubから頂いてくると、サンプルが一杯あって、楽しめるぞ。 ただ pip するだけじゃ、もったいない。
matplotlibってグラフを扱かうライブラリィーとばかり思っていたけど、図形 まで描画できるのね。Matplotlib
あっ、こんな記事もあるな。 Pythonのスーパーセットで高速な新プログラミング言語「Mojo」
python++ って、言うらしい。猫も杓子も、、、だな。