Tag Archives: lisp

The less familiar parts of Lisp for beginners — summary N, P

I’ve written a few posts about features of the Lisp language that a newcomer arriving from C++ might not have encountered.  I’m going through them alphabetically, so here is a summary page of the functions beginning with the letters N and P:

nconc

next-method-p

notany

notinline

pairlis

peek-char

print

pprint-dispatch

pprint-exit-if-list-exhausted

pprint-fill, pprint-linear, pprint-tabular

pprint-indent

pprint-logical-block

pprint-newline

pprint-pop

pprint-tab

print-object

print-unreadable-object

proclaim

prog and prog*

progv

The less-familiar parts of Lisp for beginners — progv

Continuing our survey of obscure Lisp features, next is the progv special operator.  This is a feature that allows the creation or local override of dynamic (special) variables at runtime.  It binds the supplied dynamic variable names to supplied values for the duration of the progv block.  There are some good examples in the CLHS, and I’ll review them briefly here.

The first example shows an existing special variable whose value is temporarily replaced within the progv, and in any functions called from it.  When the progv form exits, the special variable reverts to its former value.  If this is unfamiliar to you, review the side discussion on special variables in the earlier article about print.

Here’s the first example, adapted from the CLHS:
*slime-repl sbcl*

CL-USER> (defparameter *x* 1)
*X*
CL-USER> *x*
1
CL-USER> (progv '(*x*) '(2) *x*)
2
CL-USER> *x*
1

In the second example, a local variable is declared in a let, and the progv form lies underneath that.  Despite the fact that the progv is nested within the let, it does not shadow the definition in the let, so a bare evaluation of the symbol returns the value assigned from the let.  Note, though, that let does not intern a symbol, so symbol-value sees the value defined in the progv form.  Also, the print-x function I define in the labels form sees the dynamic value of x, even though it is not passed as a parameter.  The example, adapted from the CLHS, is here:
*slime-repl sbcl*

CL-USER> (labels
             ((print-x ()
                (declare (special x))
                (format t "~A~%" x)))
           (let ((x 3))
             (progv '(x) '(4)
               (print-x)
               (list x (symbol-value 'x)))))
4
(3 4)

The less-familiar parts of Lisp for beginners — prog and prog*

Next in our survey of possibly unfamiliar Lisp features is a pair of somewhat unusual macros, prog and prog*.  These macros fall squarely into the category of “syntactic sugar”.  There’s nothing particularly special about these, they simplify the establishment of a particular sort of mini-environment.

Within prog, the programmer can declare, and optionally initialize, variables.  Then, after an optional declaration (see declare), appears a sequence of go tags and statements.  A go tag is any bare symbol or integer, not in parentheses, and is not evaluated.  A statement is enclosed in parentheses, and is evaluated when flow encounters it.  Within the statements, the programmer will typically use go to branch to a go tag in the prog body.  Execution of the prog ends when flow passes to the end of the list of statements, or if a return statement is encountered (the entire body is enclosed in an unnamed block).

The typical use case for this is a state machine.  Variables are assigned, flow enters the body, and operations are performed on data, with branches to different tags based on the values encountered.

The difference between prog and prog* is exactly like that between do and do*, or let and let*, in the variable declaration region.  The * form of the macro allows variables declared in the list to depend on earlier variables in the same declaration.

The less-familiar parts of Lisp for beginners — print-unreadable-object

Having discussed pretty-printing and print-object, now we come to a macro, print-unreadable-object, that is used to simplify the printing of objects that are deemed unreadable.  You’ve probably seen such output in the past, when printing instances of CLOS classes.  Where arrays and lists might print their contents, the Lisp printer just produces a brief output to indicate the class from which this instance was built, and an implentation-defined representation of the instance’s identity (often a memory address).

The programmer is likely to use this macro in a custom print-object method, to augment the normal printed representation of the class rather than printing the full contents.  The HyperSpec contains a good example of the use in that case.  Note that it can be used in other contexts, as follows:
*slime-repl sbcl*

CL-USER> (let ((mylist '(1 2 3)))
           (print-unreadable-object
               (mylist *standard-output* :type t :identity t)
             (format t "{{Uninteresting contents}}")))
#<CONS {{Uninteresting contents}} {1004DDE997}>
NIL

The less-familiar parts of Lisp for beginners — print-object

We’ve come to the end of pretty-printing, at least for the moment, and continue our walk through the less commonly used parts of Common Lisp with the print-object generic function.  We’ve mentioned this function briefly in passing a few times already, a good example would be this early post.

The programmer must not call the print-object method directly, but that doesn’t mean it isn’t interesting to the programmer.  The way the programmer typically interacts with this method is by specializing it on a new class or structure.  The example post linked to above does that, for the doubly-linked list structures I was reviewing at the time.

The difficulty with the doubly-linked list structure was that, if you created one with two or more elements in it, and found yourself trying to display it to the user, the internal circularity of the structure led to an infinite loop during output, which was irritating during development.  By specializing print-object on the structure, I was able to print out the contents of the list without the internal circularity being a problem.

The version of the function that I used there isn’t really complete, it’s just something short for debugging purposes.  Properly, print-object should acknowledge the special variables that control printing, and format the output appropriately.  The relevant variables are:

  • *print-readably* which should produce output that would recreate the list if presented to the Lisp reader.  Look at the earlier example for make-load-form.
  • *print-escape* of which *print-readably* is a superset, should also produce output suitable for reading into the Lisp reader.
  • *print-pretty* which should produce output intended to be more easily understood by humans, typically by the introduction of additional formatting whitespace.
  • *print-length* which indicates how many elements in a sequence should be printed before the rest of the sequence is elided.
  • *print-level* which is handled by the implementation if the print-object method obeys a simple restriction, that nested structures are handled by passing the sub-elements to write or similar output functions, not descended internally in the function itself.  This allows the printer to keep track of the level of nesting that is being printed.
  • *print-circle* which indicates that the calling context wants circularity detection to be performed, and if that requires special behaviour in the print-object method, it has to be coded to handle that case.
  • *print-radix* and *print-base* which affect the printing of rational numbers.  The programmer is unlikely to have to take special action on these variables, and can probably let them be passed down to the function responsible for printing the numeric values.
  • *print-case* which affects how symbol names are output.  Also unlikely to require special action by the programmer.
  • *print-gensym* which affects the output of uninterned symbol names, such as those returned by gensym.  Once more, the programmer is unlikely to have to write special code to respond to the value of this variable in print-object.
  • *print-array* which determines whether non-string arrays should have their contents printed, or whether a short specifier should be output instead.

The print-object generic function should return a single value, the object passed in for printing.  That is also something that was not correctly done in the earlier example.

Finally, now that we’ve covered *print-circle*, I should point out that that is another way to avoid the circularity problem printing out doubly-linked lists.  Rather than defining a print-object method, I could have done my coding in an environment where *print-circle* is non-nil.  In that case, the circularity detection allows the printer to avoid the infinite loop, and doubly-linked lists can be printed:
*slime-repl sbcl*

CL-USER> (let ((dl (dl-list:make-dl-list)))
           (dl-list:push-front dl 10) 
           (dl-list:push-front dl 20) 
           dl)
#S(DL-LIST::DL-LIST
   :FIRST-NODE #1=#S(DL-LIST::DL-NODE
                     :VALUE 20
                     :NEXT-NODE #2=#S(DL-LIST::DL-NODE
                                      :VALUE 10
                                      :NEXT-NODE NIL
                                      :PREV-NODE #1#)
                     :PREV-NODE NIL)
   :LAST-NODE #2#)