(rontolisp) docs
← リファレンス

clojure.pprint

プリティプリント、つまりデータを右マージンの内側に収まるようにレイアウトして出力する名前空間です。 レイアウトはディスパッチ関数を通して決まり、プログラムはこの関数を拡張することも置き換えることも できます。clojure.pprint を require すると使えます。Clojure の同名の名前空間について文書化された 振る舞いをもとに rontolisp 向けに書いた Clojure ソースで、改行の判断は Clojure のプリティプリンタと 同じ判断をするレイアウトエンジンが行います。すべてのバックエンドで同じように動きます。

var振る舞い
pprint(pprint x)、(pprint x writer): x を *print-right-margin* の内側にレイアウトして *out*(または writer)へ書き、最後に改行する
pp(pp): *1 の pprint
write(write x & options): オプションに従って x を書く。:stream(ライター。既定の true は *out*、nil なら文字列を返す)、:pretty、:right-margin、:miser-width、:dispatch、:length、:level、:readably、:suppress-namespaces、:base、:radix
print-table(print-table rows)、(print-table ks rows): rows のマップを表として出力する。列は ks のキーごとに 1 つで右寄せ(ks を省くと最初の行のキー)
simple-dispatch既定のディスパッチ。class で振り分けるマルチメソッドで、プログラムは自分のレコードや型のメソッドを追加できる
code-dispatchClojure のコード用のディスパッチ。これも class で振り分けるマルチメソッドで、定義や制御のフォームをそれぞれ固有のレイアウトで出力する
*print-pprint-dispatch*、with-pprint-dispatch、set-pprint-dispatchpprint が各値を渡す関数。本体の間だけ束縛するか、置き換える
pprint-logical-block(pprint-logical-block options* body): body を論理ブロック(レイアウトが改行するかどうかを判断する単位)として実行する。オプションは :prefix、:per-line-prefix、:suffix。*print-level* より深いと # を書く
print-length-loop本体を最大 *print-length* 回実行し、打ち切ったところで ... を書く loop
write-out(write-out x): ブロックの中で x をディスパッチ経由で書く
pprint-newline(pprint-newline kind): 条件付き改行。:linear(ブロックが収まらないとき改行)、:fill(次の部分が行に収まらないとき改行)、:miser(miser スタイルのときだけ改行)、:mandatory
pprint-indent(pprint-indent relative-to n): ブロックの継続行のインデントを、ブロックの開始位置(:block)または現在の桁(:current)から n 桁にする
fresh-line進行中のプリティプリントが行頭でなければ改行する。プリティプリントの外では常に改行する
*print-right-margin*、*print-miser-width*マージン(既定 72、nil で無制限)と、ブロックの開始位置がマージンにどこまで近づくと miser スタイルになるか(既定 40、nil で常に通常スタイル)
*print-pretty*、*print-suppress-namespaces*、*print-base*、*print-radix*write の既定値。プリティプリントする、名前空間を残す、10 進、基数の印なし
pprint-tabClojure と同じく UnsupportedOperationException を投げる
get-pretty-writer受け取ったライターをそのまま返す
cl-format(cl-format writer control & args): control に書いた Common Lisp の format 指示子で args を整形する。writer が nil なら文字列を返し、true なら *out* へ、それ以外なら writer へ書く。cl-format を参照
formatter、formatter-out(formatter control): ライターと引数を受け取って cl-format と同じように整形する関数。制御文字列のコンパイルは一度だけ行う。(formatter-out control): 引数を受け取ってその時点の *out* へ書く関数で、ディスパッチ関数の中で使う

行の残りに収まるコレクションはその行に出力します。収まらないコレクションは要素を 1 行に 1 つずつ置き、 マップのエントリもそれだけで収まらなければ、値をキーの下の行へ送ります。*print-length*、 *print-level*、*print-meta*、*print-namespace-maps* は pr と同じように効き、マップやセットの 要素は pr が出力する順に並びます。

{:id 7,
 :scores [0 3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57],
 :tags [:admin :dev]}
(defn
 greet
 [name]
 (str
  "Hello, "
  name
  "!"))

|       :lang | :year |
|-------------+-------|
|     Clojure |  2007 |
| Common Lisp |  1984 |

write に :stream nil を渡すと文字列が返り、with-out-str は pprint の出力を文字列として捕らえます。

simple-dispatch にメソッドを追加すると、プログラム自身の型の出力を決められます。

{:price <120 JPY>}

独自のディスパッチ関数は、論理ブロックと条件付き改行で値をレイアウトします。

<0 1 2 3 4 5 6 7 8 9 10
 11 12 13 14 15 16 17
 18 19>

code-dispatch は Clojure のプリティプリンタと同じようにコードをレイアウトします。defn、let、 if、cond、condp、->、ns などはそれぞれ固有のレイアウトで、無名関数のフォームは #(...) リテラルとして出力します。

(defn greet
  "Greets a person."
  [person]
  (let [n (:name person)]
    (when (seq n) (println "Hello," n "- glad to see you again"))))
#(+ %1 (* %2 %2))

cl-format

cl-format は Clojure の値を対象にした Common Lisp の format です。~A と ~S は print と pr と同じように書き、~{ は任意のコレクションやシーケンスを走査し、~:[ は Clojure の真偽で 判定します。そのため false は nil と同じく最初の節を選びます。

指示子書くもの
~A、~S引数を print / pr と同じように書く。整数と比は *print-base* と *print-radix* に従う。~mincol,colinc,minpad,padcharA で幅を埋め、@ を付けると左側を埋める
~D、~B、~O、~X、~radixR整数を 10、2、8、16 進または radix 進で書く。~mincol,padchar,commachar,intervalD の形で指定し、: で桁を区切り、@ で正の数にも符号を付ける
~R、~:R、~@R、~:@R数を英語の基数詞、英語の序数詞、ローマ数字、古い形式のローマ数字で書く
~P、~@P引数が 1 でなければ s(ies)を書く。: を付けると一つ前の引数を見る
~C、~:C、~@C文字そのもの、文字の名前、pr と同じ表記
~F、~E、~G、~$数を固定小数点、指数、一般、金額の各表記で書く。パラメータは Common Lisp と同じ
~%、~&、~\|、~~、~T改行、行頭でなければ改行、改ページ、チルダ、指定の桁までの空白
~*、~:*、~@*引数を飛ばす、前に戻る、指定の位置へ移る
~[...~;...~]、~:[、~@[引数で節を選ぶ。添字で選ぶ、真偽で選ぶ、真のときだけ実行する
~{...~}、~:{、~@{、~:@{本体を繰り返す。コレクションの要素ごと、その部分リストごと、残りの引数ごと、残りの引数を部分リストとして
~^、~:^引数(~:^ は部分リスト)が残っていなければ、囲んでいる実行を終える
~(...~)、~:(、~@(、~:@(本体を小文字にする、各単語の先頭を大文字にする、最初の単語の先頭を大文字にする、大文字にする
~?、~@?別の制御文字列を、リスト引数に対して、または残りの引数に対して実行する
~<...~>節を幅の中に揃えて配置する
~W、~<...~:>、~_、~I引数をプリティプリントのディスパッチで書く、論理ブロック、条件付き改行(: は fill、@ は miser、:@ は mandatory)、インデント
There are 3 results: 46, 38, 22
1,234,567 forty-two third MCMXCIV
3.14|  1.235E+4|1.50|000000ff
Hello World Hello LOUD
1, 2, 3|<1 2><3 4>|left           right|
name        lang        year

プリティプリント用の指示子は、進行中のプリティプリントに出力を加えます。そのため、ディスパッチ関数は formatter-out で値をレイアウトできます。プリティプリントの外では、プリティライターを必要とする 制御文字列(~W、~<、~T、~& を含むもの)が専用のプリティライターを使い、0 桁目から出力します。

{"name":"rontolisp",
 "scores":
 [0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44,
  48, 52, 56],
 "tags":["lisp", "clojure", "wasm"]}

書式の誤った制御文字列は RuntimeException になり、そのメッセージには制御文字列と、誤りの位置を 指す ^ が入ります。

違い

  • 10 進小数のリテラルはここでは比なので、1.5M の ~A は 3/2 を書きます。また整数が long として オーバーフローすることはなく、-9223372036854775808 の ~D は、Clojure が例外を投げるところで 値をそのまま書きます。
  • Clojure の拒否メッセージが JVM 自身のもの(*out* がプリティライターでないときのプリティプリント用 指示子の ClassCastException や、NullPointerException)である場合、クラスは同じでメッセージが 異なります。
  • get-pretty-writer は受け取ったライターをそのまま返します。pprint や write は呼び出しごとに 出力を 0 桁目からレイアウトし、マージンには実行時に束縛されている値を使います。Clojure の プリティライターは、作られたときのマージンを保ち、それまでにそのライターへ書かれた内容の続きの桁から レイアウトします。