đź“ťCommon Lisp

tags

Lisp #programming-language

Common Lisp is a practical lisp

Lisp exposes two levels of syntax (s-expressions and lisp forms)

Syntax

Evaluation

Functions

;; general form
(defun name (parameters)
  "docstring."
  body)

;; optional parameters
(defun f (a b &optional c d) …)

;; specifying default value
(defun f (&optional (a 10)) …)

;; to know whether value was supplied
(defun f (&optional (a 3 a-supplied-p)) …)
;; “-supplied-p” suffix is a convention for such variables


;; rest
(defun f (a b &rest cs) …)


;; keyword
(defun f (&key a b c) …)
;; … then called
(f :a a-value :c c-value)
;; can also supply default value and a supplied-p
(defun f (&key (a 10 a-supplied-p)) …)
;; keyword can also be customized to be different from variable name
(defun f (&key ((:apple a)) ((:box b) 0 b-supplied-p)) …)

;; order:
;; 1. required
;; 2. &optional
;; 3. &rest
;; 4. &key

;; When both optional and keyword parameters are used, optional will
;; eat keywords until optional parameters are satisfied.
;;
;; You should probably avoid using optional and key arguments
;; together.
(defun foo (x &optional y &key z) (list x y z))
(foo 1 :z 3) ; => ERROR
(defun bar (a &optional b c &key d) (list a b c d))
(bar 1 :d 2) ; => (1 :D 2 NIL)

;; When both rest and keyword parameters are used, the arguments are
;; filled in both rest and keyword parameters.
(defun baz (&rest rest &key a b c) (list rest a b c))
(baz :a 1 :b 2 :c 3) ; => ((:A 1 :B 2 :C 3) 1 2 3)
;; This definition only allows specified keyword arguments and no
;; other arguments:
(baz "hello" "world") ; => ERROR: Unknown &KEY argument: "hello"
(baz :hello "world")  ; => ERROR: Unknown &KEY argument: :HELLO
;; To allow other arguments, add &allow-other-keys to the parameters
;; list

;; RETURN-FROM operator can be used to return value from the function
;; immediately
(defun foo (n)
  (dotimes (i 10)
    (dotimes (j 10)
      (when (> (* i j) n)
        (return-from foo (list i j))))))

;; get function object
#'foo

;; call it
(funcall #'foo 20)
(apply #'foo '(20))

;; anonymous functions
(lambda (parameters) body)

Variables

;;; defining global variables
;; If variable is already defined, its value is not overwritten.
(defvar *name* optional-value
  "optional docstring.")

;; `defparameter' always assigns the new value.
(defparameter *name* value
  "optional docstring.")

;; `defconstant' name cannot be used as a function parameter or
;; rebound with any other binding form. Many Lisp programmers follow
;; the plus +naming+ +convention+ for constants.
(defconstant name initial-value-form
  "optional docstring.")

;; All global variables are dynamically-scoped. (The name of every
;; variable defined with `defvar' or `defparameter' is automatically
;; declared “special.”) LET variables or function parameters can
;; override it.
(defvar *x* 10)
(defun foo () (format t "X: ~d~%" *x*))
(foo) ; => X: 10
(let ((*x* 20)) (foo)) ; => X: 20
(foo) ; => X: 10

In Common Lisp, all global variables are automatically “special” (use dynamic scoping)

In Common Lisp, global variables use star *naming* *convention* because of dynamic scoping

Loops

;; basic form
(do (variable-definition*)
    (end-test-form result-form*)
  statement*)
;; where variable-definition =
(var init-form step-form)


;; LOOP simple form—an infinite loop. Iterates forever unless you
;; `return' or break out.
(loop
  body-form*)

Macros

;; Macro parameters are destructuring. Macros can also have &body
;; parameters that work identically to &rest but IDEs can use it to
;; properly indent macros.
(defmacro do-primes ((var start end) &body body)
  …)

;; Use `gensym' if you need to generate a unique symbol.
(defmacro with-gensyms ((&rest names) &body body)
  `(let ,(loop for n in names collect `(,n (gensym)))
     ,@body))

(defmacro once-only ((&rest names) &body body)
  (let ((gensyms (loop for n in names collect (gensym))))
    `(let (,@(loop for g in gensyms collect `(,g (gensym))))
      `(let (,,@(loop for g in gensyms for n in names collect ``(,,g ,,n)))
        ,(let (,@(loop for n in names for g in gensyms collect `(,n ,g)))
           ,@body)))))

Data structures

Association list

Property list

Common Lisp: Multiple Dispatch

Common Lisp: classes

Slots inheritance

During inheritance, all slot specifiers with the same name are merged to create a single slot specifier.

Multiple inheritance and class specificity

Common Lisp: Format

Common Lisp: condition system

Common Lisp: special operators

Common Lisp: multiple values

Common Lisp: packages and symbols

Common Lisp: readtable

Resources

Backlinks