Land of Lispを読んでいます。日本語版も英語版も英語電子版も持っているのに、読み終わる前に投げ出して、また最初から読み始めるということを何度も繰り返しています。以下、日本語版と英語Kindle版へのアフィリンクです。
本書で使用しているCommon Lisp処理系はCLISPなのですが、ネットで見かけるLisperたちは「開発段階ではコンパイルの速いClozure Lisp、デプロイはSBCL」と言っていることが多いので、僕もSBCLを使って読み進めています。
第7章でdot->png
という関数が登場するのですが、その中(p.115の7行目)に
(ext:shell (concatenate 'string "dot -Tpng -O " fname))
という部分があります。ここで使われているext:shell
はCLISP独自の命令なので、SBCLで動かすには書き換えないといけません。
さいわい少し調べただけで、SBCLでシェルからプログラムを実行するにはsb-ext:run-program
を使えばよいと分かりました(SBCLマニュアルより7.7.3 Running external programs)。sb-ext:run-program
は実行するプログラム名とそのプログラムへの引数リストの2つを指定して呼び出します。プログラム名はフルパスで書く必要があるようです(シェルからサーチパスを取ってくるなどすればよいのかもしれませんが……)。
最初は
(sb-ext:run-program "/usr/local/bin/dot" '("-Tpng" "-O" fname))
でいけると勘違いしていたのですが、これだとfname
に入っているファイル名が展開されないので、
(sb-ext:run-program "/usr/local/bin/dot" `("-Tpng" "-O" ,fname)))
とquasi-quoting(準クォート)してやることで解決しました。
結果として、SBCLで動くdot->png
は以下のようになりました。
(defun dot->png (fname thunk) (with-open-file (*standard-output* fname :direction :output :if-exists :supersede) (funcall thunk)) (sb-ext:run-program "/usr/local/bin/dot" `("-Tpng" "-O" ,fname)))
-Tpng
を-Tpdf
とかにすると、さらにきれいなグラフが得られます。
……と、作業し終えたところで下のようなページを見つけました。同じくsb-ext:run-program
を使っていますがdot
を直接起動するのではなくsh
を通して起動するようになっていて、僕のコードよりも環境非依存に近いかと思います。