Skip to content

LISP - Formatting with Format

A Practical Guide to Lisp’s format Function

Section titled “A Practical Guide to Lisp’s format Function”

The format function in Common Lisp is a uniquely powerful tool for text formatting and output. It acts like a mini-language within Lisp, allowing you to produce simple or complex strings with precise control over presentation. It’s far more capable than simple string concatenation or the printf found in other languages.

(format destination control-string &rest arguments)
  • destination: Where the output goes. Common values are t (for standard output, the console), nil (to return the formatted text as a new string), or a stream.
  • control-string: A string containing plain text and special format directives. Each directive starts with a tilde (~).
  • arguments: The values to be formatted, one for each directive that requires an argument.

Here’s a breakdown of the most essential directives, grouped by category.

  • ~A (Aesthetic): Prints an argument in a human-readable format. Good for most general purposes. (format nil "Hello, ~A!" "World") -> "Hello, World!"
  • ~S (S-Expression): Prints an argument in a Lisp-readable format (an S-expression), with quotes for strings and symbols. (format nil "The value is ~S." "a string") -> "The value is \"a string\"."
  • ~% (Newline): Inserts a newline character.
  • ~~ (Tilde): Inserts a literal tilde character.
  • ~D (Decimal): Prints an integer in base 10.
  • ~B (Binary): Prints an integer in base 2.
  • ~X (Hexadecimal): Prints an integer in base 16 (uppercase).
  • ~F (Floating-point): Prints a float. Can take parameters for width and precision.
  • ~R (Radix): Prints an integer in any base from 2 to 36, or as English words (e.g., (format nil "~R" 27) -> "twenty-seven").

Using nil as the destination is perfect for building strings programmatically.

(let ((user "Alice")
(items 5))
(let ((message (format nil "User ~S has ~D item(s) in their cart." user items)))
(print message)))
"User \"Alice\" has 5 item(s) in their cart."

Directives can take prefix parameters (mincol, padchar) to control alignment and padding. The format is ~<mincol>,<padchar><directive>.

;; Print the number 5 as a binary string, padded with '0' to a minimum width of 8.
(format t "~8,'0B~%" 5)
;; Print a string right-aligned in a column of 10 characters.
(format t "|~10A|~%" "test")
00000101
| test|
  • Structured Logging: format is ideal for creating detailed, well-formatted log messages. You can easily include timestamps, severity levels, and structured data.
  • Generating Reports: Use it to generate simple text-based reports, CSV files, or other line-based data formats.
  • Readability: For complex formatting, especially with conditional logic (~[) or iteration (~{), the format string can become hard to read. Consider breaking complex logic into helper functions and keeping the control string relatively simple.
  • Security Note: When incorporating user input into a format string, always pass it as an argument to a directive (like ~A). Never construct the control-string itself from untrusted input, as this can lead to security vulnerabilities (a format string attack).

This tutorial only scratches the surface. The Common Lisp Hyperspec entry for format is the definitive reference. Explore advanced directives like ~{...~} for iteration over lists and ~[...~] for conditional formatting to unlock its full potential.