Skip to content

LISP - Program Structure

Modern Lisp - Program Structure and Execution

Section titled “Modern Lisp - Program Structure and Execution”

A Lisp program is built from S-expressions (Symbolic Expressions). An s-expression is a textual representation for nested list data structures. In Lisp, code is data, and s-expressions are the data structure used to represent the code. The fundamental building blocks of s-expressions are atoms (like numbers 42, symbols my-variable, and strings "hello") and lists (sequences of atoms or other lists, enclosed in parentheses, like (+ 2 3)).

Lisp programs are typically developed interactively using a REPL (Read-Eval-Print Loop). Modern Common Lisp implementations, such as SBCL (Steel Bank Common Lisp) or CCL (Clozure CL), are high-performance compilers that compile code on-the-fly, giving you the feel of an interpreter with the speed of compiled code.

The REPL is the heart of interactive Lisp development. It performs a simple, powerful loop:

  1. Read: It reads the s-expression you type at the prompt.
  2. Eval: It evaluates the s-expression, executing it as code.
  3. Print: It prints the result of the evaluation back to you.
  4. Loop: It waits for your next input.

Let’s write an s-expression to find the sum of three numbers: 7, 9, and 11. At the REPL prompt (often *), you type the s-expression:

;; The '+' is the function, and the numbers are its arguments.
(+ 7 9 11)

After you press Enter, the REPL evaluates it and prints the result:

27

As you can see, Lisp uses prefix notation (also known as Polish notation). The operator or function name always comes first within the parentheses, followed by its arguments. This is a consistent rule across the entire language, from arithmetic to complex operations.

For example, the standard infix mathematical expression (10 - 4) * 3 would be written in Lisp’s prefix notation as:

;; Prefix notation: operator first, then operands.
(* (- 10 4) 3)

Let’s take another example: converting a temperature of 68°F to Celsius. The formula is C = (F - 32) * 5/9.

;; Lisp code for Fahrenheit to Celsius conversion.
;; Note that 5/9 produces a rational number, ensuring precision.
(* (- 68 32) 5/9)

The REPL evaluates this and returns:

20

For larger programs, you’ll write code in source files, typically with a .lisp extension. You can then load this file into your running Lisp environment or compile it.

;;; main.lisp - A simple Lisp program example.
;; Define a function to convert Fahrenheit to Celsius.
(defun fahrenheit-to-celsius (temp-f)
"Converts a temperature from Fahrenheit to Celsius."
(* (- temp-f 32) 5/9))
;; Call the function and print the result using FORMAT.
;; ~a is a placeholder for an aesthetic representation of the value.
;; ~% adds a newline.
(format t "68F is ~aC.~%" (fahrenheit-to-celsius 68))

You can load and run this file from your Lisp implementation. For example, in a REPL:

(load "main.lisp")

Executing the file will produce the following output:

68F is 20C.

No programming introduction is complete without a “Hello, World!” example. Here is the modern, idiomatic way to do it in Common Lisp.

;; Using format to print to the standard output stream 't'.
;; ~% is the directive for a newline character.
(format t "Hello, World!~%")
(format t "I am learning modern Common Lisp!~%")

When loaded and executed, this code produces:

Hello, World!
I am learning modern Common Lisp!

To get started with modern Lisp development, consider using an integrated environment. Popular choices include:

  • Portacle: A portable, multi-platform Common Lisp environment that comes pre-configured with Emacs, SBCL, and Quicklisp.
  • Emacs + SLIME/Sly: The classic and most powerful setup for interactive Lisp development.
  • VS Code with Alive: A modern extension that brings a SLIME-like interactive experience to Visual Studio Code.

Setting up Quicklisp, the de-facto package manager for Common Lisp, is essential for using third-party libraries.