October 2011
24 posts
Initialize a vector with map-into
Novices who want an array of distinct things sometimes write something like this, where make-foo returns a fresh object of some sort: (make-array 42 :initial-element (make-foo)) This actually creates a vector containing the same identical (eq) object at all 42 indexes. The initial-element argument is evaluated only once to produce the result, and the result is used 42 times to initialize the...
Oct 29th
Graham Crackers
If you’re trying to learn Common Lisp from Paul Graham’s ANSI Common Lisp (which I don’t recommend), be sure to read Graham Crackers. These course notes outline some of the cases where the style of ANSI Common Lisp differs from good Common Lisp style.
Oct 23rd
1 note
Division shortcuts
floor, truncate, and related functions can take an optional second argument to use as the divisor. The default value is the integer 1. Instead of (floor (/ x 42)) you can use (floor x 42).
Oct 22nd
:initform and :default-initargs
There are two means of automatic initialization of CLOS slot values, :initform and :default-initargs. Chris Riesbeck makes a strong case for preferring :default-initargs. Here’s a simplified example of the syntactic difference, taken from some Quicklisp code. Consider modeling version control commands with CLOS. Here’s a possible design: (defclass vc-command () ((command ...
Oct 21st
1 note
Multiple value division
floor, truncate, and related functions return multiple values for division-related operations: the quotient, and the remainder. There are several situations where both values are useful. For example, if you have a vector of octet values and you want to find the value of a particular bit, you can use something like this: (defun bit-ref (octet-vector index) (multiple-value-bind (octet-index...
Oct 20th
The Common Lisp and Unix epochs
The Common Lisp epoch begins at 00:00 on January 1, 1900, GMT. get-universal-time returns a universal time, defined as the number of seconds elapsed since then. The Unix epoch begins at 00:00 on January 1, 1970, GMT. time() returns the number of seconds elapsed since then. It’s easy to get the difference between a Common Lisp universal time and a Unix epoch timestamp: *...
Oct 19th
2 notes
"How do I apply AND?"
I sometimes see a question like this: “I have a list of things and I want to see if they’re all true, so how can I apply ‘and’ to it?” Since and is a macro, it can’t be applied, but there are standard functions that can answer the question instead. (every #’identity list) will return nil as soon as it encounters any nil entries in list, and true if no...
Oct 18th
Controlling loop flow with simple restarts
Sometimes you know in advance how you want to change control flow in a loop. Other times you might want to defer that decision by offering a restart. For example, here’s a loop with a pair of with-simple-restarts: (with-simple-restart (stop-processing "Stop processing users") (dolist (user (pending-user-list)) (with-simple-restart (skip "Skip user ~A" user) (process-user...
Oct 17th
Slow pretty-printing
Producing “pretty” output can be time consuming. Some implementations do a lot of work to determine whether to e.g. break lines when printing with functions like print and format. If printing is a bottleneck and aesthetic output isn’t required, binding or setting *print-pretty* to NIL can significantly improve output speed for some implementations.
Oct 16th
(setf values)
To assign the multiple return values of a function to multiple variables, you could use this: (multiple-value-setq (whole partial) (truncate x 1024)) (setf values) is more general, and works on places: (setf (values whole partial) (truncate x 1024)) (setf (values (aref v 0) (aref v 1)) (truncate x 1024))
Oct 15th
Fine-grained control flow
The “do” macros (do, do*, dolist, and dotimes) have bodies that act like tagbody. You can put go tags anywhere in the body and use go to jump to them from arbitrary places. This can be useful for skipping, retrying, or otherwise changing the flow of iteration. For example: (dolist (users (get-user-list)) :retry ... (when some-condition (go :retry) ...)
Oct 14th
Comparing many objects
The numeric comparison functions =, /=, <, <=, >, and >= can take more than two arguments. This is handy to e.g. check if several variables have monotonically increasing numeric value:  (< a b c d) For numbers in a sufficiently short list, apply does the trick: (apply #'< list) Non-numeric comparison functions generally take exactly two objects to compare, so e.g. (string= x y...
Oct 13th
:start and :end with parse-integer
parse-integer takes :start and :end arguments, so you don’t have to extract integer subsequences from strings to pass them to parse-integer. For example, to parse date strings that look like “2011-10-01” into year, month, and date integers, you can do this: (defun parse-date (string) "Parse a date string in the form YYYY-MM-DD and return the year, month, and day as multiple...
Oct 12th
1 note
Converting characters to integers
If you have the character #\7 and you want the integer 7, you might be tempted to use (parse-integer (string char)) or even this ASCII-oriented technique: (- (char-int char) (char-int #\0)) While the former is specified to give the right answer, the latter will only work by coincidence. The spec does discuss character ordering, but it makes no guarantees about the values returned by char-int or...
Oct 11th
Multi-line format control strings
You can break up long format control strings with ~ at the end of a line. For example: * (format t "It was the best of times, ~ it was the worst of times.") It was the best of times, it was the worst of times. The ~, newline, and all whitespace following the newline are removed from the output, so you can align the continued control string with the previous line. The : and @...
Oct 10th
PAIP lessons
Paradigms of AI Programming is a great book for learning Common Lisp. Peter Norvig wrote a retrospective on the book and included this list of 52 important lessons: Use anonymous functions. [p. 20] Create new functions (closures) at run time. [p. 22] Use the most natural notation available to solve a problem. [p. 42] Use the same data for several programs. [p. 43] Be specific. Use...
Oct 9th
2 notes
Stylish Common Lisp
The Tutorial on Good Lisp Programming Style by Peter Norvig and Kent Pitman is full of useful tips for Common Lisp programmers.
Oct 8th
2 notes
Touching a file
To create an empty file, like the Unix touch command does, you might try something like this: ;; BOGUS (close (open "foo.txt" :direction :output :if-does-not-exist :create :if-exists :append)) open has a :direction option specifically for this purpose, though: (open "foo.txt" :direction :probe :if-does-not-exist :create) If “foo.txt” does not exist, it...
Oct 7th
1 note
Reading floats
When the reader sees a number like “3.0” with no exponent marker, the reader will convert it into a single-float by default. You can change what float type is used for conversion by changing *read-default-float-format* to another float type. For example: * (/ 22.0 7.0) 3.142857 * (setf *read-default-float-format* 'double-float) DOUBLE-FLOAT * (/ 22.0 7.0) 3.142857142857143 The...
Oct 6th
Redirecting output
Got a function that writes to *standard-output* but you really want to redirect it somewhere else? You can bind the *standard-output* special variable in all the macros that create temporary streams. For example, to return the output as a string: * (with-output-to-string (*standard-output*) (print-marketing-report)) "Source,Hits twitter,243 google,805 direct,47 " To write it out to a...
Oct 5th
Swapping places
The naive way to swap the values of two places, a and b, is something like this: ;; BOGUS (setf temp a) (setf a b) (setf b temp) psetf (parallel setf) can do it in one form: (psetf a b b a) But rotatef is best: (rotatef a b)
Oct 4th
3 notes
Pluralization
The ~P format directive can do simple pluralization. * (format nil "You have ~D goat~:P." 42) "You have 42 goats." * (format nil "You have ~D goat~:P." 1) "You have 1 goat." * (format nil "You have ~D fl~@:P." 42) "You have 42 flies." * (format nil "You have ~D fl~@:P." 1) "You have 1 fly." Irregular plurals are more complicated: (format nil "You have ~D ~:*~[mice~;mouse~:;mice~]." n) ...
Oct 3rd
1 note
string output streams
get-output-stream-string doesn’t just return the string accumulated so far in a string-stream. It also resets the accumulation, so you can use the same stream multiple times for separate results. Here’s a simple string splitter: (defun split (string &optional (split-character #\Space)) (let ((result '()) (stream (make-string-output-stream))) (loop for char across...
Oct 2nd
3 notes
Discarding output
Unix shell nerds discard unwanted output by redirecting it to /dev/null. The equivalent in Common Lisp is the empty broadcast stream returned by a call to make-broadcast-stream with no arguments. For example, if you have some code that normally prints to *standard-output*, but you want that output discarded, you can do something like this: (let ((*standard-output* (make-broadcast-stream))) ...
Oct 1st