Monthly Archives: April 2014

The less-familiar parts of Lisp for beginners — pprint-newline

Continuing our discussion of pretty-printing, we arrive at pprint-newline.  This is another function that is used inside the environment set up within the context of pprint-logical-block.  The pprint-newline function takes a ‘kind’ argument that can be one of four possible keyword values.

If kind is :linear, a newline will be printed only if the entire output of the section cannot fit on a single line.  In that case, all such linear-mode newlines will be output.  In the typical usage, this means you either print all objects on one line, or each object on its own line.  Compare this to the pprint-linear function.

If the kind is :miser, then this function inserts a newline exactly like :linear, but only when in “miser mode”.  Miser mode takes effect whenever the start of the printing block is closer to the right margin than the value of the variable *print-miser-width*.  If miser mode is not in effect, this function never inserts a newline.

If the kind is :fill, then this function inserts a newline only when the current line cannot hold the next object to be printed.  The effect is to put as many objects on each line as possible before starting a new line.  Compare this to the pprint-fill function.

If the kind is :mandatory, the function always inserts a newline, unconditionally.

You should use pprint-newline in pprint-logical-block blocks, and avoid the use of format or terpri functions, as the latter do not integrate with the formatting behaviour of pretty-printing.  For instance, the pprint-indent function, which only takes effect after the next newline, is not guaranteed to do anything if you use format or terpri instead of pprint-newline.

The less-familiar parts of Lisp for beginners — pprint-logical-block

Our exploration of pretty-printing has now reached the point where we’ll show real code instead of just describing some functions.  We’ve arrived at pprint-logical-block, which is the starting point for constructing pretty-printing functions.

The pprint-logical-block macro sets up a pretty-printing context inside of which the programmer writes his or her pretty-printing directives.  The required arguments are the stream and the object to be printed.  If the object to be printed is not a list, this macro simply sends the object to write, but if it is a list, then objects in the list can be retrieved with pprint-pop, and the logical block is exited by calling pprint-exit-if-list-exhausted.

One important restriction is that pprint-logical-block must not modify the values of variables not bound within the block itself.  The reason for this is that, during circularity detection, the entire block may be executed more than once, causing these side-effects to be invoked an unpredictable number of times.

So, now we will define a special pretty-printing function.  This function will act on lists whose first element is the keyword :SPECIAL.  In that case, this first entry in the list is skipped, and the following entries are printed out, one to a line, with an index number and the type, enclosed in brace brackets instead of parentheses, and with an SP: prefix to denote this behaviour:
pprint-logical-block.lisp

(defun my-special-pprint (stream obj)
  (pprint-logical-block (stream obj 
                                :prefix "SP: { "
                                :suffix "}")
    (let ((ctr 0))
      (pprint-pop)
      (pprint-newline :mandatory stream)
      (do ()
          (nil)
        (pprint-exit-if-list-exhausted)
        (let ((entry (pprint-pop)))
          (write entry :stream stream)
          (pprint-tab :section-relative 6 6 stream)
          (format stream
                  "<--- Entry #~D.  ~A" 
                  ctr (type-of entry)))
        (incf ctr)
        (pprint-newline :mandatory stream)
        ))))

Next is the function that we use to demonstrate the new printing.  Notice that I set the *print-pretty* special variable in an enclosing let form to allow automatic restoration of its value after the various setf calls have finished modifying it.  We discussed this, and special variables in general, as an aside in the article on print.  Here is the function:
pprint-logical-block.lisp

(defun demonstrate ()
  (set-pprint-dispatch '(cons (member :SPECIAL))
                       'my-special-pprint 10.0)

  (let ((list-1 (list 1.0d0 "2" :THREE '(:SPECIAL 4.0d0) 5.0d0))
        (list-2 (list :SPECIAL 1.0d0 "2" :THREE '(:SPECIAL 4.0d0) 5.0d0))
        (*print-pretty* nil))

    (setf *print-pretty* nil)
    (format t "Non-pretty-printing a list:~%")
    (print list-1)
    (setf *print-pretty* t)
    (terpri)
    (terpri)
    (terpri)
    (format t "Pretty-printing the same list:~%")
    (print list-1)
    (terpri)
    (terpri)
    (terpri)
    (setf *print-pretty* nil)
    (format t "Non-pretty-printing another list:~%")
    (print list-2)
    (terpri)
    (terpri)
    (terpri)
    (setf *print-pretty* t)
    (format t "Pretty-printing the second list:~%")
    (print list-2)
    (values)))

Finally, here is the output. You’ll notice that this function is recursively dispatched when appropriate.
*slime-repl sbcl*

CL-USER> (demonstrate)
Non-pretty-printing a list:

(1.0d0 "2" :THREE (:SPECIAL 4.0d0) 5.0d0) 


Pretty-printing the same list:

(1.0d0 "2" :THREE
 SP: {
       4.0d0       <--- Entry #0.  DOUBLE-FLOAT
       }
 5.0d0) 


Non-pretty-printing another list:

(:SPECIAL 1.0d0 "2" :THREE (:SPECIAL 4.0d0) 5.0d0) 


Pretty-printing the second list:

SP: {
      1.0d0       <--- Entry #0.  DOUBLE-FLOAT
      "2"         <--- Entry #1.  (SIMPLE-ARRAY CHARACTER (1))
      :THREE      <--- Entry #2.  KEYWORD
      SP: {
            4.0d0       <--- Entry #0.  DOUBLE-FLOAT
            }           <--- Entry #3.  CONS
      5.0d0       <--- Entry #4.  DOUBLE-FLOAT
      } 
; No value

The less-familiar parts of Lisp for beginners — pprint-indent

We continue through our list of more obscure parts of Lisp, and our current focus on the pretty-printer, with pprint-indent.

This function must be called inside a pprint-logical-block block.  It has the effect of changing the indentation that will be used by the pretty-printer after the next newline.  There are two ways it can be used, with :BLOCK or with :CURRENT.

When called with the :BLOCK argument, this sets the indentation relative to the first character of the current block.  That is, if the current block can be thought of as a rectangular column between a left indent and a right margin, pprint-indent :BLOCK moves the left margin by an amount equal to its argument.  The argument can be negative, increasing the size of the printable column, but cannot push the left margin to the left of the end of the per-line prefix string, if any.

When called with the :CURRENT argument, this sets the indentation relative to the current position of the cursor on the line.

Captchas enabled

I’ve enabled captchas on the site, using the WordPress plugin here.  The site was gathering a few hundred spams a day for moderation, which is just too annoying.  I’ve selected numbers only, no words, because Chin Yi’s postings are in traditional Chinese , and that’s the native language of this WordPress installation… it might confuse English visitors to be asked to solve for X in:  X – 六 = 9

I’ll be watching the moderation queue for indications of problems.

The less-familiar parts of Lisp for beginners — pprint-fill, pprint-linear, pprint-tabular

We’ve been looking over the pretty-printing functions recently.  These functions, pprint-fill, pprint-linear, and pprint-tabular, are used in the pretty-printing of lists.  Their special behaviour is only manifested when the *print-pretty* variable is non-nil.

The pprint-fill function prints as many list elements on a line as possible before inserting a newline.  Naturally, this raises the question of what the Lisp image thinks is the line length.  The standard defines a variable, *print-right-margin*, which, if set, is taken to be the maximum line length.  If this variable is nil, then the maximum line length is determined in an implementation-defined manner.  If the current cursor position is not at the left margin, the printing is indented appropriately on the left, so that the screen region being considered for printing is narrowed appropriately.

The pprint-linear function will either print all of the list elements on a single line, or if that would exceed the length of the line, prints exactly one element per line.  The behaviour when the cursor is not in the left column is the same as the case above.

The pprint-tabular function prints elements in a tabular fashion, with consecutive elements being printed left-to-right.  The tabsize optional parameter determines the number of spaces from the beginning of one column to the beginning of the next.  The behaviour when the cursor is not in the left column is the same as the case above.

Here are some examples to demonstrate the behaviour of these functions:
*slime-repl sbcl*

CL-USER> (setq *print-pretty* t)
T
CL-USER> (setq *print-right-margin* 50)
50
CL-USER> (let (demolist)
           (dotimes (i 6)
             (push (* i 10000) demolist))
           (princ "Demolist is: ")
           (pprint-linear t demolist))
Demolist is: (50000 40000 30000 20000 10000 0)
NIL
CL-USER> (let (demolist)
           (dotimes (i 7)
             (push (* i 10000) demolist))
           (princ "Demolist is: ")
           (pprint-linear t demolist))
Demolist is: (60000
              50000
              40000
              30000
              20000
              10000
              0)
NIL
CL-USER> (let (demolist)
           (dotimes (i 7)
             (push (* i 10000) demolist))
           (princ "Demolist is: ")
           (pprint-fill t demolist))
Demolist is: (60000 50000 40000 30000 20000 10000
              0)
NIL
CL-USER> (let (demolist)
           (dotimes (i 7)
             (push (* i 10000) demolist))
           (princ "Demolist is: ")
           (pprint-tabular t demolist t nil 10))
Demolist is: (60000     50000     40000     30000
              20000     10000     0)
NIL