Edited at

CLtL2: 第27章 プリティプリント

More than 5 years have passed since last update.

Advent Calendar 2012と言いながら年を越してしまったらいかにも申し訳ないので、遅ればせながら参加することにしました。最初から、多分三回くらいの記事になるのではないかと思っていたので、年内は軽く助走的に始めます。

プリティプリントと言えば、何となくそれはきれいにインデントをつけて印刷してくれるもの、と思っていらっしゃる方は大勢いると思います。でもそれを実際にこの27章の記述に従って書こうとすると、なかなか一筋なわではいかず、結局普通のformat文できれいに印刷しておしまい、という方も大勢いらしゃるのではないでしょうか。

プリティプリントを使った場合と使わない場合で何がちがうかというと、印刷時の有効幅に合わせて成型してくれるということです。逆に言うと、そういうようにコマンドなり、フォーマット制御文なりを使うということです。たとえば、以下のようなテキストがあったとしましょう。

(defun scheme (&optional x)

"A Scheme read-eval-print loop (using interp).
Handles call/cc by explicitly passing continuations."

;; Modified by norvig Jun 11 96 to handle optional argument
;; instead of always going into a loop.
(init-scheme-interp)
(if x
(interp x nil #'print)
(loop (format t "~&==> ")
(interp (read) nil #'print))))

そしてちょっと変則的ですが、例題として以下のようなことをしてみます。

cg-user(3): (setq foo 

'(defun scheme (&optional x)
"A Scheme read-eval-print loop (using interp).
Handles call/cc by explicitly passing continuations."

;; Modified by norvig Jun 11 96 to handle optional argument
;; instead of always going into a loop.
(init-scheme-interp)
(if x
(interp x nil #'print)
(loop (format t "~&==> ")
(interp (read) nil #'print)))))

ここでクォートをつけていることをお見逃しなく。

すると、Windows が広い場合にはこのように印刷されますし、

cg-user(4): foo

(defun scheme (&optional x)
"A Scheme read-eval-print loop (using interp).
Handles call/cc by explicitly passing continuations."

(init-scheme-interp)
(if x (interp x nil #'print) (loop (format t "~&==> ") (interp (read) nil #'print))))

狭い場合にはこんな風に印刷されます。

cg-user(5): foo

(defun scheme (&optional x)
"A Scheme read-eval-print loop (using interp).
Handles call/cc by explicitly passing continuations."

(init-scheme-interp)
(if x
(interp x nil #'print)
(loop (format t "~&==> ")
(interp (read) nil #'print))))

その時々の環境に合わせて、ダイナミックにインデンテーションが変化します。

世の中にはこんな機能はいらないものもあります。

たとえばセマンティックウェブ系におけるNTripleフォーマットは1トリプルは必ず1行で終わりです。しかしその拡張であるTurtleは全くjsonと似ていて、複数行に渡ったまとまりでインデンテーションがほしいものだし、XMLでも同様ですね。そんなインデンテーションは機械可読としてはあってもなくてもいいけど、人間向きにはあってほしい、みたいなものにはこういうプリティプリント機能が有効ということですね。

逆にインデンテーション依存の言語ではプリティプリントは余分な機能なのかしら。

Common Lisp のプリティプリントには関数を使う方法と、format文の制御文を使う方法があります。後者のほうが使うのは実は簡単だったりするのですが、次回はとりあえず関数を使う方法について説明します。