Jim's lisp notes , Sep 2011 * clisp is the common lisp implementation I typically use. It's consistent with Graham's lisp books, which give a good explanation. (See my AI class resource list for other online books etc.) * The fundamental idea is that evaluating (A B C) finds function (eval A) and applies it to (eval B) (eval C). > (* 3 (+ 1 4)) 15 * However, eval/lookup of symbols and functions are in different namespaces in common lisp (it's called a "lisp-2). An expression like (foo bar baz) looks for "foo" in the function table but "bar" and "baz" in the symbol table. And macros live in a bit of their own thing. > (setf x 3) ; modifiy a symbol (dynamic or lexical) > (defvar *count* 0 "objects") ; init a dynamic variable (with doc string) > (let ((x 0)) ...) ; init a lexical variable > (type-of x) > (describe 'x) > (inspect 'x) ; interactive describe > (symbol-value 'x) > 'x ; (eval 'x) ; (eval (quote x)) ; naming it and looking it up > (defun foo (x) (* 2 x)) ; define a function in global namespace > #'foo ; or (function foo) ; refer to it > (type-of #'foo) ; gives FUNCTION > (fboundp 'foo) ; is there a globl function named #'foo ? > (describe 'foo) ; smart enough to also describe #'foo > (defmacro inc (x) `(setf ,x (1+ ,x))) ; define a macro > (macro-function 'inc) ; refer to it > (type-of (macro-function 'inc)) ; gives FUNCTION > (describe 'inc) ; read about it > (macroexpand-1 '(inc x)) ; see it happen > (fboundp 'inc) ; T for macros & functions > (special-operator-p 'if) ; => T > (fdefinition 'push) ; works for functions, macros, special operators * argument lists in functions have some special conventions, particularly &key, &rest, &optional that give variations > (defun (bar &key name age) (list name age)) > (bar :name "Jim") ; returns ("Jim" nil) * "packages" manage namespaces for lookup of strings to symbols ; it's the typical chunk of lisp definitions . Modules (*modules* currently loaded) are similar but can contain multiple packages. Use defpackage, in-package to create one and move into it. (require 'new-package) is similar to (load "file") but only gets function,symbol names named in :export > *package* ; current package namespace > package::variable ; full name of internal variable in other package > package:variable ; name of external variable in other package Default clisp package at prompt is user ; full name common-lisp-user . http://www.gigamonkeys.com/book/programming-in-the-large-packages-and-symbols.html describes some of the "gotchas", including : To find out what package a symbol came from originally, evaluate > (package-name (symbol-package 'some-symbol)) Other package related commands : load file read and eval a file. The orig package is restored after. make-package create a new package namespace in-package move into the namespace of a package and work there use-package get all the symbols that some other package exports import go get a symbol from some other package intern create an internal symbol * (describe thing) is very helpful; looks up variables/function/etc (apropos "phrase" &optional package) is also pretty helpful (inspect jim) may also help; more interactive (documentation thing) Also in clisp, at the > prompt, typing ? (or :h or help) gives some information; more within error environments. (which disolay as e.g. "Break 1 [11]> " ) * set, setq, setf : the assignment thingy, set and its cousins, has gone through several iterations. See http://stackoverflow.com/questions/869529 for the details. The bottom line now is to setq (set quote) doesn't do what setf (set field) does, but setf does what setq does. So use setf. * booleans are T and nil ; nil is same as () empty list. * printing is done with (format stream "template ..." var1 var2 var3) where stream is T for stdout and template uses things like ~s for "as string", ~% for newline, e.g. > (setf x 4) > (format t "x is ~s ~%" x) * Lists are the fundamental data structure. They're built of linked 'cons' structures. These all create the same list : > '(1 2 3) ; or (quote (1 2 3)) which is the same > (list 1 2 3) > (cons 1 (cons 2 (cons 3 nil))) Given a list, car and cdr (also called first, rest) get the parts of a cons. There are a lot of tricky implications and uses of these linked lists - look up the difference between (append ...) and (nconc ...) for example. * But common lisp has many other data structures as well: * arrays (n-dim; make-array) and vectors (1-dim) > (setf vec #(a b c)) ; or (vector a b c) > (format t "0th element is ~s ~%" (aref vec 0)) ;; read > (setf (aref vec 0) 23) ;; write A 2dim matrix works like this: > (setf matrix (make-array '(2 2) :initial-element 0)) > (setf (aref matrix 0 0) 1) => #2A((1 0) (0 0)) * hash tables See http://www.lispworks.com/documentation/HyperSpec/Body/f_mk_has.htm for options, particularly :test that sets how keys are compared. > (setf person (make-hash-table)) > (setf (gethash 'name person) "Jim") > (setf (gethash 'age person) 52) > (format t (%s is %s ~%) (gethash 'name person) (gethash 'age person)) * objects via defstruct, defmethod, defclass (CLOS) ; the fields are called "slots"; see slot-value, slot-exists-p, etc > (defstruct person (name "") (age 0)) > (setf jim (make-person :name "Jim")) > (format t (%s is %s ~%) (person-name jim) (slot-value jim 'age)) > (apropos "struct") ; oodles of symbols, functions with that name > (structure-slots 'person) ; list of slots in person ;; could loop over slots with something like : > (slot-value jim (slot-definition-name (first (structure-slots 'person)))) These can be input using their printed representations, starting with syntax like #s(foo ) or #2a((1 0) (0 0)) * variable declarations: let, let*, destructuring-bind boundp : is this symbol bound in the global environment? > (setf x 2) (boundp 'x) => T ; top-level; dynamic > (let ((x 2)) (boundp 'x)) => nil ; lexical > (let ((x 2)) (declare (special x)) (boundp 'x)) T ; dynamic * let and let* are used to set up local variables, both inside and outside functions. And functions defined within a let have those variables in their closure, which gives them a permanance. let* assigns its variables sequentially; let doesn't and so they can't depend on each other. > (let ((counter 0)) ; ((val1 init1) (val2 init2)) (defun get-counter () counter) (defun inc-counter () (incf counter))) > (inc-counter) > (get-counter) 1 * loops & conditionals: if, cond, do, mapcar & variations The most typical brancing constructs are (if ...) and (cond ...). Common loops are dotimes, dolist, and (do ...) itself, which is a bit tricky but very powerful. See http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node84.html I don't like (loop ...) itself much; it uses a fairly non-lisp-ish syntax. See http://cl-cookbook.sourceforge.net/loop.html for examples. Functional approaches with mapcar, mapcons and recursion are popular with lispers; * #+feature and #-feature are called "feature expressions; can be used to include/exclude stuff based on the lisp implementation; see http://www.cs.cmu.edu/Groups/AI/html/faqs/lang/lisp/part2/faq-doc-17.html * installed quicklisp.org ; 'net lisp package installer uses ASDF (another system definition facility) ; see http://common-lisp.net/~mmommer/asdf-howto.shtml > (ql:system-apropos "unit-test") > (ql:quickload "unit-test") > (apropos "unit-test") ; show what just happened ... but I can't find teh docs on how to use it. * compilation of *.lisp to *.fas can be done via (compile-file "filename). (load "file") will grap the .fas if it's up to date. Also, *.lib files are generated and used by the (require ...) directive. And to speed up clisp startup, memory images *.mem can stored and reloaded with (saveinitmem "file") and "clisp -M file". Options to (saveinitmem) can make standalone executables. And .mem can be compressed with gzip to save space. * lisp testing http://aperiodic.net/phil/archives/Geekery/notes-on-lisp-testing-frameworks.html says to use lisp-unit ; see http://www.cs.northwestern.edu/academics/courses/325/readings/lisp-unit.html It looks good; I've put it in ./utilities/ * numbers See parsing of numbers and symbols http://www.ida.liu.se/imported/cltl/clm/node189.html Besides the expected integers and floats, lisp also understands "ratios" > (+ 3/5 7/8) ; 3/5 is a numeric input form like 1.2e6 41/28 and complex numbers > (* #c(0 1) #c(0 1)) -1 * printed representation Usually the output at the prompt of a lisp data structure can also be used to read it back in. However, these representations can be implementation dependent, and typically don't eval the interior parts and so can't be used for complex expressions. http://www.ida.liu.se/imported/cltl/clm/node191.html#SHARPSIGNMACROCHARACTERSECTION For example wih a hash > (setf h (make-hash-table)) > (setf (gethash :color h) "red") > (setf (gethash :age h) 42) > h #S(HASH-TABLE :TEST FASTHASH-EQL (:AGE . 42) (:COLOR . "red")) > (setf g #s(hash-table :test eq (:size . 'big) (:color "blue"))) or a structure > (defstruct person age color) (make-person :age 'old :color 'red) #S(PERSON :AGE OLD :COLOR RED) The "#" character is particularly important in all this; it's a "dispatching macro character" for the reader. See http://www.ida.liu.se/imported/cltl/clm/node190.html for details. When the reader see # it chooses a function based on char (ignoring case as usual). Here's a table of some of the variations: #' #'foo is a shortcut for (function foo) #S( ) structure including defstruct, hash-table #2A(..) array, in this case 2D #(1 2 3) simple vector i.e. 1D array ; (vector #C(1 1) complex number ; (complex 1 1) #B101 binary #Xf0 hex #O37 octal #\a the character "a" #*1011 bit vector #:foo an "uninterned" symbol; macros and (gensym) use 'em #.foo (eval foo) at read/compile time | Same for interactive, #,foo (eval foo) at load time | but different for compiled. #+feature | lisp implementation flags; symbol following is ignored #-feature | or not depending on what's in *features* global. #| .. |# block comment; analogous to /* ... */ in C # something output by print that cannot be read back in * In addition, he interactive prompt (i.e. the REPL read-eval-print-loop) interprets a few characters differently than the lisp evaluation itself. For example the "?" char : > ? ; interactive means "help" You are in the top-level Read-Eval-Print ... > (setf ? 3) (eval ?) ; lisp sees it as a symbol 3 * The AIMA utilities.lisp file has a number of good examples of helper functions, loops, and macros.