Land of Lisp第7章

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:shellCLISP独自の命令なので、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を通して起動するようになっていて、僕のコードよりも環境非依存に近いかと思います。

lambdacadabra.blogspot.com