String Formatting in Lisp

Our first program demonstrates string formatting in Lisp. Here’s the full source code with explanations:

(defpackage :string-formatting
  (:use :cl))

(in-package :string-formatting)

(defstruct point
  x y)

(defun main ()
  ;; Lisp offers several formatting options for different data types.
  ;; We'll use the format function to demonstrate these.

  ;; Formatting a struct
  (let ((p (make-point :x 1 :y 2)))
    (format t "struct1: ~a~%" p)
    (format t "struct2: ~s~%" p))

  ;; Formatting types
  (format t "type: ~a~%" (type-of (make-point :x 1 :y 2)))

  ;; Formatting booleans
  (format t "bool: ~a~%" t)

  ;; Formatting integers
  (format t "int: ~d~%" 123)
  (format t "bin: ~b~%" 14)
  (format t "char: ~c~%" #\!)
  (format t "hex: ~x~%" 456)

  ;; Formatting floats
  (format t "float1: ~f~%" 78.9)
  (format t "float2: ~e~%" 123400000.0)
  (format t "float3: ~E~%" 123400000.0)

  ;; Formatting strings
  (format t "str1: ~a~%" "\"string\"")
  (format t "str2: ~s~%" "\"string\"")

  ;; Formatting with width specifications
  (format t "width1: |~6d|~6d|~%" 12 345)
  (format t "width2: |~6,2f|~6,2f|~%" 1.2 3.45)
  (format t "width3: |~6@<~,2f~>|~6@<~,2f~>|~%" 1.2 3.45)
  (format t "width4: |~6a|~6a|~%" "foo" "b")
  (format t "width5: |~6@<~a~>|~6@<~a~>|~%" "foo" "b")

  ;; Using format to return a string
  (let ((s (format nil "format-to-string: a ~a" "string")))
    (format t "~a~%" s))

  ;; Writing to a stream other than standard output
  (with-open-file (stream "error.log" :direction :output :if-exists :supersede)
    (format stream "io: an ~a~%" "error")))

(main)

To run the program, save it as string-formatting.lisp and use your Lisp implementation to load and execute it. For example, with SBCL:

$ sbcl --script string-formatting.lisp
struct1: #S(POINT :X 1 :Y 2)
struct2: #S(STRING-FORMATTING::POINT :X 1 :Y 2)
type: STRING-FORMATTING::POINT
bool: T
int: 123
bin: 1110
char: !
hex: 1C8
float1: 78.9
float2: 1.234e8
float3: 1.234E8
str1: "string"
str2: "\"string\""
width1: |    12|   345|
width2: |  1.20|  3.45|
width3: |1.20  |3.45  |
width4: |   foo|     b|
width5: |foo   |b     |
format-to-string: a string

This example demonstrates various string formatting techniques in Lisp:

  1. We use the format function for all our formatting needs. It’s a powerful and flexible function in Lisp.

  2. The ~a directive is used for aesthetic printing, ~s for standard printing (which includes quotes for strings), and ~% for newlines.

  3. For integers, ~d is used for decimal, ~b for binary, ~c for character, and ~x for hexadecimal representation.

  4. Floats can be formatted using ~f for fixed-point notation and ~e or ~E for exponential notation.

  5. Width specifications can be added to control the field width and precision. For example, ~6d specifies a field width of 6 for integers.

  6. Left-justification can be achieved using the @< and > modifiers.

  7. The format function can write to different streams. By default, it writes to t (standard output), but we can also write to files or strings.

This Lisp code provides equivalent functionality to the original Go example, demonstrating Lisp’s powerful string formatting capabilities.