Common Lisp Tips

Sep 15

A brief history of Lisp

For a 1500-word history of Lisp up to the point of Common Lisp standardization, see section 1.1.2 of the spec. It covers the institutions, projects, people, and influential ideas involved in the creation and evolution of Lisp over the course of several decades, from McCarthy at Dartmouth in the 1950s to the many active branches of Lisp in the 1980s.

Sep 14

Putting the R in REPL

Try this in your REPL:

* (let (#'42) (+ . #'5))
=> 47

If you find it perplexing, and you use SBCL, evaluating + next in the REPL might help clear things up.

Using an adjustable displaced array as a cursor on another array.

Scanning a string can be done using input functions withwith-input-from-string:

(with-input-from-string (stream "Hello World!  How do you do? ")
  (let ((c (make-string 4)))
    (loop
      :for pos = (read-sequence c stream)
      :while (= pos (length c))
      :do (print c)
      :finally (terpri))))

"Hell" 
"o Wo" 
"rld!" 
"  Ho" 
"w do" 
" you" 
" do?" 
nil

This can also be done using a displaced adjustable array, without copying the data that is read:

(defun make-vector-cursor (vector &key (size 0) (offset 0))
  (make-array size
              :element-type (array-element-type vector)
              :adjustable t
              :displaced-to vector
              :displaced-index-offset offset))

(defun advance-cursor (cursor &key (size (length cursor)))
  (multiple-value-bind (vector offset) (array-displacement cursor)
    (adjust-array cursor size
                  :element-type (array-element-type vector)
                  :displaced-to vector
                  :displaced-index-offset (+ offset (length cursor)))))
(let ((c (make-vector-cursor "Hello World!  How do you do? " :size 4)))
  (loop
    :do (print c)
    :while (ignore-errors (advance-cursor c))
    :finally (terpri)))

"Hell" 
"o Wo" 
"rld!" 
"  Ho" 
"w do" 
" you" 
" do?" 
NIL
(let ((c (make-vector-cursor "Hello World!  How do you do? " :size 1)))
  (loop
    :for size :from 1
    :do (print c)
    :while (ignore-errors (advance-cursor c :size size))
    :finally (terpri)))

"H" 
"e" 
"ll" 
"o W" 
"orld" 
"!  Ho" 
"w do y" 
"ou do? " 
nil

This post courtesy of Pascal J. Bourguignon

Sep 09

Binding keyword arguments

By default, keyword argument variable bindings match the name of the keyword used to pass the value. For example:

(defun keytest (&key foo)
  (list foo))

* (keytest :foo 42)
=> (42)

However, the variable doesn’t have to match the keyword provided. The following syntax will accept a keyword of :foo in the function call but bind a variable named bar:

(defun keytest (&key ((:foo bar)))
  (list bar))

* (keytest :foo 42)
=> (42)

Binding keywords this way can be helpful when binding a plist via destructuring-bind when you don’t want the plist keys to name the variables you actually want to use in the scope of the destructuring bind. For example, the plist may contain (:customer-id 42 ...), but in your context it makes more sense to bind a variable named old-customer-id.

The “keyword” also need not be a keyword:

(defun keytest (&key ((foo bar)))
  (list bar))

* (keytest 'foo 42)
=> (42)

Using internal symbols as function keyword arguments is one way to indicate that they are not part of a function’s public API.

Sep 06

Multiple export clauses in defpackage

The syntax for defpackage allows multiple export clauses. I like to use this feature to visually group related symbols.

(defpackage #:myproject
  (:use #:cl)
  ;; Web stuff
  (:export #:fetch
           #:parse-url
           #:status)
  ;; File utilities
  (:export #:lines
           #:first-line
           #:touch)
  ...)

Although it has no effect on the semantics, I find it helpful for reading.

Sep 05

A simple REPL

Here’s a very simple REPL that includes the *, **, and *** variables:

(defun repl ()
  (princ "> ")
  (loop 
    (shiftf *** ** * (eval (read))) 
    (format t "~a~&> " *)))
  

Provided by Stas Boukarev.

Apr 10

Printing package-qualified symbols

When *print-escape* is true, symbols are normally printed with package prefixes only if the current package *package* is not the symbol’s home package. It’s easy to make sure that a symbol is always printed with a package prefix, e.g. for debugging.

When the current package is the keyword package, non-keyword symbols are printed with package prefixes, and keywords are printed with their normal colon prefix. For example, in SBCL:

(in-package #:cl-user)
(let ((*package* (find-package "KEYWORD")))
  (prin1-to-string '(car stream :car quit)))

=> "(COMMON-LISP:CAR COMMON-LISP:STREAM :CAR SB-EXT:QUIT)"

For full details, see 22.1.3.3.1, Package Prefixes for Symbols.

Jan 03

Evaluating the last expression

In the REPL, +, ++, and +++ have as values the three most recently evaluated expressions. A quick way to evaluate the previous expression, especially handy in a REPL without input history, is

#.+

It’s equivalent to (eval +).

(Thanks to Anton Kovalenko.)

Jan 01

Un-displacing an array

Here’s a function to get the underlying array on which a displaced array is based:

(defun undisplace-array (array)
  "Return the fundamental array and the start and end positions into
it of a displaced array."
  (let ((length (length array))
        (start 0))
    (loop
      (multiple-value-bind (to offset) (array-displacement array)
        (if to
            (setq array to
                  start (+ start offset))
          (return (values array start (+ start length))))))))

From an article by Erik Naggum.

Dec 30

Referring to method parameters

In defmethod lambda lists, required parameters that aren’t explicitly specialized default to specializing on the system class t. But there’s a difference between an implicit and explicit specialization on t. The hyperspec explains:

The expansion of the defmethod macro “refers to” each specialized parameter (see the description of ignore within the description of declare). This includes parameters that have an explicit parameter specializer name of t. This means that a compiler warning does not occur if the body of the method does not refer to a specialized parameter, while a warning might occur if the body of the method does not refer to an unspecialized parameter. For this reason, a parameter that specializes on t is not quite synonymous with an unspecialized parameter in this context.

This makes a difference in Clozure CL; here’s what you get if you don’t use an implicitly specialized required parameter:

? (defmethod foo (bar) 42)
;Compiler warnings :
;   In (FOO (T)) inside an anonymous lambda form: Unused lexical variable BAR
#<STANDARD-METHOD FOO (T)>

There is no warning with an explicit specialization:

? (defmethod bar ((baz t)) 42)
#<STANDARD-METHOD BAR (T)>

(Thanks to Hans Hübner.)