Common Lisp Essentials

Basic Syntax

 1; Comments start with semicolon
 2
 3;; Variables
 4(defvar *global-var* 42)  ; Global variable (convention: *name*)
 5(defparameter *param* 100) ; Always re-evaluated
 6(let ((x 10) (y 20))      ; Local variables
 7  (+ x y))
 8
 9;; Constants
10(defconstant +pi+ 3.14159) ; Convention: +name+
11
12;; Functions
13(defun square (x)
14  "Return the square of x"
15  (* x x))
16
17(defun greet (name)
18  (format t "Hello, ~a!~%" name))
19
20;; Lambda
21(lambda (x) (* x x))
22((lambda (x) (* x x)) 5) ; => 25
23
24;; Multiple values
25(defun divide-with-remainder (a b)
26  (values (floor a b) (mod a b)))
27
28(multiple-value-bind (quotient remainder)
29    (divide-with-remainder 17 5)
30  (format t "~a remainder ~a~%" quotient remainder))

Data Structures

Lists

 1;; Create lists
 2'(1 2 3 4)
 3(list 1 2 3 4)
 4(cons 1 (cons 2 (cons 3 nil)))
 5
 6;; Access elements
 7(first '(1 2 3))  ; => 1
 8(car '(1 2 3))    ; => 1
 9(rest '(1 2 3))   ; => (2 3)
10(cdr '(1 2 3))    ; => (2 3)
11(nth 2 '(a b c d)) ; => C (0-indexed)
12
13;; List operations
14(append '(1 2) '(3 4))    ; => (1 2 3 4)
15(reverse '(1 2 3))        ; => (3 2 1)
16(length '(1 2 3))         ; => 3
17(member 2 '(1 2 3))       ; => (2 3)
18(remove 2 '(1 2 3 2 4))   ; => (1 3 4)
19
20;; Association lists
21(defvar *alist* '((a . 1) (b . 2) (c . 3)))
22(assoc 'b *alist*)        ; => (B . 2)
23(cdr (assoc 'b *alist*))  ; => 2

Vectors (Arrays)

 1;; Create vector
 2(vector 1 2 3 4)
 3#(1 2 3 4)
 4
 5;; Access elements
 6(aref #(1 2 3) 1)  ; => 2
 7
 8;; Modify
 9(let ((v (vector 1 2 3)))
10  (setf (aref v 1) 99)
11  v)  ; => #(1 99 3)
12
13;; Length
14(length #(1 2 3))  ; => 3

Hash Tables

 1;; Create hash table
 2(defvar *ht* (make-hash-table))
 3
 4;; Set values
 5(setf (gethash 'key1 *ht*) 100)
 6(setf (gethash 'key2 *ht*) 200)
 7
 8;; Get values
 9(gethash 'key1 *ht*)  ; => 100, T
10(gethash 'key3 *ht* 'default)  ; => DEFAULT, NIL
11
12;; Iterate
13(maphash (lambda (k v)
14           (format t "~a => ~a~%" k v))
15         *ht*)
16
17;; Remove
18(remhash 'key1 *ht*)

Control Flow

Conditionals

 1;; if
 2(if (> x 10)
 3    (print "Greater")
 4    (print "Not greater"))
 5
 6;; when (no else clause)
 7(when (> x 10)
 8  (print "Greater")
 9  (do-something))
10
11;; unless
12(unless (< x 0)
13  (print "Non-negative"))
14
15;; cond (multiple conditions)
16(cond
17  ((< x 0) "Negative")
18  ((= x 0) "Zero")
19  ((> x 0) "Positive")
20  (t "Unknown"))  ; t is default case
21
22;; case (switch)
23(case (day-of-week)
24  ((monday tuesday wednesday thursday friday) "Weekday")
25  ((saturday sunday) "Weekend")
26  (otherwise "Unknown"))

Loops

 1;; dotimes (count loop)
 2(dotimes (i 5)
 3  (print i))
 4
 5;; dolist (iterate list)
 6(dolist (item '(a b c))
 7  (print item))
 8
 9;; loop macro (powerful)
10(loop for i from 1 to 10
11      collect i)  ; => (1 2 3 4 5 6 7 8 9 10)
12
13(loop for i from 1 to 10
14      when (evenp i)
15      collect i)  ; => (2 4 6 8 10)
16
17(loop for x in '(1 2 3 4 5)
18      sum x)  ; => 15
19
20(loop for i from 1 to 100
21      while (< i 50)
22      collect i)
23
24;; do (general loop)
25(do ((i 0 (1+ i)))
26    ((>= i 5))
27  (print i))

Higher-Order Functions

 1;; map
 2(mapcar #'square '(1 2 3 4))  ; => (1 4 9 16)
 3(mapcar #'+ '(1 2 3) '(10 20 30))  ; => (11 22 33)
 4
 5;; filter
 6(remove-if-not #'evenp '(1 2 3 4 5 6))  ; => (2 4 6)
 7(remove-if #'oddp '(1 2 3 4 5 6))       ; => (2 4 6)
 8
 9;; reduce
10(reduce #'+ '(1 2 3 4 5))  ; => 15
11(reduce #'max '(3 1 4 1 5 9 2 6))  ; => 9
12
13;; apply
14(apply #'+ '(1 2 3))  ; => 6
15
16;; funcall
17(funcall #'+ 1 2 3)  ; => 6

Macros

 1;; Simple macro
 2(defmacro when-positive (x &body body)
 3  `(when (> ,x 0)
 4     ,@body))
 5
 6(when-positive 5
 7  (print "Positive")
 8  (print "Yes"))
 9
10;; Macro with gensym (avoid variable capture)
11(defmacro with-gensyms (syms &body body)
12  `(let ,(mapcar (lambda (s) `(,s (gensym))) syms)
13     ,@body))
14
15;; Anaphoric if
16(defmacro aif (test then &optional else)
17  `(let ((it ,test))
18     (if it ,then ,else)))
19
20(aif (find 'x '(a b x c))
21     (format t "Found: ~a~%" it)
22     (format t "Not found~%"))

CLOS (Common Lisp Object System)

 1;; Define class
 2(defclass person ()
 3  ((name :initarg :name
 4         :accessor person-name)
 5   (age :initarg :age
 6        :accessor person-age
 7        :initform 0)))
 8
 9;; Create instance
10(defvar *john* (make-instance 'person
11                              :name "John"
12                              :age 30))
13
14;; Access slots
15(person-name *john*)  ; => "John"
16(setf (person-age *john*) 31)
17
18;; Methods
19(defmethod greet ((p person))
20  (format t "Hello, I'm ~a~%" (person-name p)))
21
22(greet *john*)
23
24;; Inheritance
25(defclass employee (person)
26  ((company :initarg :company
27            :accessor employee-company)))
28
29;; Multiple dispatch
30(defmethod combine ((x number) (y number))
31  (+ x y))
32
33(defmethod combine ((x string) (y string))
34  (concatenate 'string x y))
35
36(defmethod combine ((x list) (y list))
37  (append x y))

Practical Examples

File I/O

 1;; Read file
 2(with-open-file (stream "file.txt")
 3  (loop for line = (read-line stream nil)
 4        while line
 5        collect line))
 6
 7;; Write file
 8(with-open-file (stream "output.txt"
 9                        :direction :output
10                        :if-exists :supersede)
11  (format stream "Hello, World!~%"))
12
13;; Read S-expressions
14(with-open-file (stream "data.lisp")
15  (read stream))

Error Handling

 1;; handler-case (like try-catch)
 2(handler-case
 3    (/ 1 0)
 4  (division-by-zero ()
 5    (format t "Cannot divide by zero~%"))
 6  (error (e)
 7    (format t "Error: ~a~%" e)))
 8
 9;; unwind-protect (like finally)
10(unwind-protect
11    (progn
12      (open-resource)
13      (use-resource))
14  (close-resource))  ; Always executed

String Operations

 1;; Concatenate
 2(concatenate 'string "Hello" " " "World")
 3
 4;; Format
 5(format nil "~a is ~d years old" "John" 30)
 6
 7;; Subseq
 8(subseq "Hello World" 0 5)  ; => "Hello"
 9
10;; Search
11(search "World" "Hello World")  ; => 6
12
13;; Replace
14(substitute #\- #\Space "Hello World")  ; => "Hello-World"

Quicklisp (Package Manager)

1;; Load Quicklisp
2(load "~/quicklisp/setup.lisp")
3
4;; Install package
5(ql:quickload "alexandria")
6(ql:quickload "cl-ppcre")  ; Regex library
7
8;; Use package
9(use-package :alexandria)

Further Reading

Related Snippets