📝Common Lisp

tags
Lisp #programming-language

Common Lisp is a practical lisp

Format arguments

~{ ~}
loop over the list, consuming as many elements as necessary
~:[ false-case ~; true-case ~]
use different format depending on the boolean value of the variable
~a
“aesthetics.” "Hello"Hello, :helloHELLO.
~10t
“tabulation.” Add spaces to move to N-th column.
~%
newline

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

Syntax

  • CL has fractional numbers:

    CL-USER> (+ 3/7 5/4)
    47/28
    
  • Symbols:

    • When reading symbol, the reader converts all unescaped chars to uppercase
    • Common conventions:

      • *global-variable*
      • %low-level-function or %%low-level-function (used by some programmers)
      • something->other — conversion function
  • reader macros

    • 'x(quote x)
    • #'x(function x)

Evaluation

  • It is possible for symbols to be self-evaluated—the value of the variable is the symbol itself

    (defvar t 't)
    (defvar nil 'nil)
    
  • When the reader interns keyword, it automatically defines a constant variable with the name and with the symbol as the value

    (defvar :hello ':hello)
    

    (keywords are just symbols starting with :)

  • lists:

    • function call forms
    • macro forms
    • special forms

      • 25 of them (if, let, quote)
  • nil is false, everything else is true
  • nil is both an atom and a list. (eq nil ()) => T

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)
;; it also does seem to allow only specified keyword arguments:
(baz "hello" "world") ; => ERROR: Unknown &KEY argument: "hello"
(baz :hello "world")  ; => ERROR: Unknown &KEY argument: :HELLO

;; 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)))))

Backlinks