2

I am trying to print a sequence such that neither the whole sequence is printed on one line, nor is each element of the sequence printed on its own line. E.g.

[10 11 12 13 14 15 16 17 18 19
 20 21 22 23 24 25 26 27 28 29]

I found pprint-newline in the documentation which indicates that allows me to determine how the newline gets printed. Unfortunately, I cannot find any examples on how it is to be used in conjunction with pprint, and the doc string doesn't to offer much insight:

-------------------------
clojure.pprint/pprint-newline
([kind])
  Print a conditional newline to a pretty printing stream. kind specifies if the 
newline is :linear, :miser, :fill, or :mandatory. 

This function is intended for use when writing custom dispatch functions.

Output is sent to *out* which must be a pretty printing writer.

pprint specifies an optional second argument for the writer, which is by default set to *out*. However, I am not sure how to 'send' pprint-writer to *out* in this case, e.g. something like the example below doesn't appear to work

(clojure.pprint/pprint [1 2 3 4] (*out* (clojure.pprint/pprint-newline :miser)))
dtg
  • 1,803
  • 4
  • 30
  • 44

2 Answers2

3

While Guillermo explained how to change the dispatch for pretty-printing in general, if all you want to do is printing one collection differently, that's possible, too.

For example, using cl-format (after (use '[clojure.pprint :as pp)):

(binding [pp/*print-pretty* true
          pp/*print-miser-width* nil
          pp/*print-right-margin* 10]
  (pp/cl-format true "~<[~;~@{~a~^ ~:_~}~;]~:>~%" '[foo bar baz quux]))

Set *print-right-margin* as you wish.

You don't have to use format for this. The format directives can be translated to their respective pretty-printer functions, if you want. Explanation of the format string: ~< and ~:> establish a logical block. Inside the block, there are three sections separated by ~;. The first and last section are your prefix and suffix, while the elements are printed in the middle section, using ~@{ and ~}. For each element, the element is printed using ~a, followed by a space, if needed, and a conditional fill-style newline.

(In CL, the format string could be simplified to "~<[~;~@{~a~^ ~}~;]~:@>~%", but that doesn't seem to work in Clojure 1.5.)

danlei
  • 14,121
  • 5
  • 58
  • 82
  • Thanks for the solution - it works perfectly. However, can you please tell me what you mean by the following: "The format directives can be translated to their respective pretty-printer functions, if you want". Would this entail writing a dispatch function as Guillermo indicated below? Perhaps that would be a better alternative to the arcane CL style `format` string... – dtg Oct 19 '13 at 05:51
  • There is a correspondence between the format directives and the functions in Guillermo's answer: `~< … ~:>` is `pprint-logical-block`, `~@{ … ~}` is `print-length-loop`, etc. Note that I'm using `~:_`, corresponding to `(pprint-newline :fill)`, not `:linear`. You *should* be able to use these functions directly for printing, not just for dispatching, but you'll have to set up everything properly, i.e. use `get-pretty-writer` with `*out*` etc. Just `binding` it didn't work for me, though. I had some success with `set!`, but that feels hackish, so check the documentation (or source) for that. – danlei Oct 19 '13 at 13:17
  • Thanks again. I might have to break open the Common Lisp hyperspec and read up on the CL formatting... – dtg Oct 19 '13 at 18:09
  • 1
    You're welcome. Yes, reading about the CL pretty-printer would certainly help. But while the Clojure pretty-printer is strongly influenced by it (XP), and the general concepts should be the same, there will be differences under the hood. (Like setting up `*out*` correctly, as mentioned above.) If all you want to do is print one collection, the `cl-format` solution should suffice. Sure, it looks rather arcane, but on the other hand, it's a powerful, compact DSL for formatted output. For anything more complex (e.g. a custom data format or language), I'd suggest creating a custom dispatch table. – danlei Oct 19 '13 at 19:36
1

As the help says, the function is intended for use for custom dispatch functions.

In order to change the behavior of the pprint for sequences you need to provide a new dispatch function for clojure.lang.ISeq.

The current dispatch function for sequences you can find in clojure/pprint/dispatch.clj

(use-method simple-dispatch clojure.lang.ISeq pprint-list) 
...
(defn- pprint-simple-list [alis]
    (pprint-logical-block :prefix "(" :suffix ")"
      (print-length-loop [alis (seq alis)]
        (when alis
      (write-out (first alis))
      (when (next alis)
        (.write ^java.io.Writer *out* " ")
        (pprint-newline :linear)
        (recur (next alis)))))))    

Since printing is dispatched according to data type overriding seems to be the way to go.

See the source code for ideas.

guilespi
  • 4,672
  • 1
  • 15
  • 24
  • Thank you. This seems like the way to go, ultimately. But for now, danlei's solution satisfies my requirements. – dtg Oct 19 '13 at 18:08