Symbolic Expressions (S-expressions) atoms are S-expressions lists of S-expressions are S-expressions Atoms atom turkey 1492 3turkeys u *abc$ Lists (atom) (atom turkey) (atom 1492 ocean blue) (an-atom (a list inside) and more atoms) (a list containing 5 atoms) (a list containing 8 atoms and a list (that contains 4 atoms)) (((a list containing a list containing a list of 11 atoms))) () (a list that ends with the null list ()) (not a list (not) a list )not again The Lisp evaluation rule To evaluate an atom: If itıs a numeric atom, the value is the number Else it must be a variable symbol, so the value is the value of the variable To evaluate a list: assume the first item of the list is a function, and apply that function to the values of the remaining elements of the list. Numeric S-expressions (+ 1 1) (* 23 13) (+ 1 (* 23 13)) (+ (* 2 2) (- 10 9)) (* 2 2 2 2) (sqrt (* 2 2 2 2)) (/ 25 5) (/ 38 4) (sqrt -4) (/ 23 0) (* 123456789 987654321 999999999 12345678987654321) Taking lists apart The first element of a list (be it an atom or another list) is the car of the list. the car of (alphabet soup) is alphabet the car of ((pickles beer) alphabet (soup)) is (pickles beer) the car of (((miro (braque picasso))) leger) is ((miro (braque picasso))) Everything except the first element of a list is the cdr of the list. the cdr of (alphabet soup) is (soup) the cdr of ((pickles beer) alphabet (soup)) is (alphabet (soup)) the cdr of (((miro (braque picasso))) leger) is (leger) Given a complex S-expression, you can obtain any of its component S-expressions through some combination of car and cdr. The car of the cdr of the car of ((the (nested) secret) of the (universe)) is (nested) The quote function inhibits the evaluation of its argument. It returns its argument literally. If the variable barney has the value 22, then Evaluating barney yields 22 Evaluating (quote barney) yields barney Evaluating (car (quote (betty bambam))) yields betty the single quote mark (') (itıs actually an apostrophe) can be used as an abbreviation for (quote ...). If the variable barney has the value 22, then Evaluating barney yields 22 Evaluating 'barney yields barney Evaluating (car '(betty bambam)) yields betty cons builds lists. (cons 'woof '(bow wow)) (cons '(howl) '(at the moon)) You can create any list with cons. setq assigns a value to a symbol (setq my-favorite-list '(fe fi fo fum)) my-favorite-list Note that setq is an exception to the normal evaluation rule‹the first argument is not evaluated. car, cdr, and cons are all non-destructive: (setq x '(the rain in spain)) (car x) (cdr x) (cons 'darn x) x cadr is the car of the cdr: (cadr '(old mcdonald had a farm)) cdar is the cdr of the car: (cdar '((do you)(really think so?))) There are more variations, at least up to 4 aıs or dıs: (caddar '((deep (in the (nested) structure) lies truth))) first is a synonym for car second is a synonym for cadr third is a synonym for caddr etc. rest is a synonym for cdr (setq x '(eenie meenie minie moe)) (first x) (second x) (third x) (rest x) The null list (cdr '(just-one-item)) '() (cons 'naked-atom '()) (cons 'naked-atom nil) List and append: (list 'it 'is 'really 'cold 'out) (setq brrrr (list 'it 'is 'really 'cold 'out)) (list brrrr '(i am sure you will agree)) (append brrrr '(i am sure you will agree)) brrrr A Lisp function that is called to answer a yes-or-no question is sometimes called a predicate. Predicates return nil for false. The atom t means true, and evaluates to itself. Predicates may return t for true, or they may return any other non-nil value. Predicates in Common Lisp take various forms, but sometimes end with p. (null 'fig-tree) (null '(bismark)) (null '()) (null ()) (null nil) (atom 'eggplant) (atom 99) (atom 3.141592) (atom '(floating point number)) (atom nil) (atom ()) (listp 'apple) (listp '(fish and telephones)) (listp 33) (listp nil) Some predicates take more than one argument: (> 22 11) (> 11 22) (<= 23 23) (>= 23 23) (>= 100 1) (>= 1 100) (< 1 2 3 4 5 6 7 8 9) (< 1 2 3 4 5 6 7 8 7) (equalp 'foot 'foot) (equalp 'nose 'ear) (equalp (+ 22 33 44) (* 33 3)) Common lisp has a variety of equality predicates, of which equalp is the most general (see CLtL2 p. 103). And, or, and not allow the combination of predicates into complex predicates. (setq long-list '(1 2 3 4 can I show you out the door?)) (setq lucky-number 23) (or (equalp lucky-number (car long-list)) (equalp (* (car long-list) 2) (car (cdr long-list)))) (and (equalp lucky-number (car long-list)) (equalp (* (car long-list) 2) (car (cdr long-list)))) (evenp lucky-number) (not (evenp lucky-number)) Cond is a powerful multiway branching construct. (setq x 23) (cond ((equalp x 1) '(it was one)) ((equalp x 2) '(it was two)) (t '(it was not one or two))) (setq x 2) (cond ((equalp x 1) '(it was one)) ((equalp x 2) '(it was two)) (t '(it was not one or two))) You get errors if you try to take the car or cdr of a non-nil atom (car 'foo) (cdr 'foo) You get "funny dots" if you try to cons things onto non-lists (cons 'a 'b) Although "dotted pairs" have their uses, we will ignore them for now. That means that you're probably doing something wrong if you get dots in your answers. Common Lisp provides 2 ways to comment your code: (car '(a b c)) ; this is a comment #| this could be a really big comment |# (cdr '(here is #| a list with a comment |# huh?)) Here's a constant function that takes no arguments (defun dumb-function () '(you might as well use a variable for something like this)) (dumb-function) Here's a NON-constant function that takes no arguments (defun rand8 () (random 8)) (rand8) (rand8) (rand8) (documentation 'random 'function) (arglist 'random) Here's a function that takes one argument and returns the argument plus 20: (defun add-20 (n) "returns n + 20" (+ n 20)) (add-20 15) (documentation 'add-20 'function) Here's a function that takes two arguments and returns their sum: (defun my-sum (n1 n2) "silly substitute for +" (+ n1 n2)) (my-sum 99 100) Here's a version of + that also sets the global variable *last-sum*: (defun +store (n1 n2) "Returns the sum of n1 and n2, and also sets *last-sum* to the returned value." (setq *last-sum* (+ n1 n2))) (+store 99 100) *last-sum* Here's a function that takes 3 arguments and returns a descriptive list: (defun funny-arg-lister (arg1 arg2 arg3) (cons (cons 'arg1 (cons arg1 nil)) (cons (cons 'arg2 (cons arg2 nil)) (cons (cons 'arg3 (cons arg3 nil)) nil)))) (funny-arg-lister 'a 'b '(x y z)) Here's a cleaner version of funny-arg-lister using the LIST function: (defun funny-arg-lister (arg1 arg2 arg3) (list (list 'arg1 arg1) (list 'arg2 arg2) (list 'arg3 arg3))) (funny-arg-lister 'a 'b '(x y z)) Here's another simple function (defun double-cons (one-thing another-thing) "Returns the result of consing one-thing onto another-thing twice" (cons one-thing (cons one-thing another-thing))) (double-cons 'hip '(hooray)) (double-cons 1 nil) (double-cons 1 (double-cons 1 nil)) (defun quadruple-cons (one-thing another-thing) "Returns the result of consing one-thing onto another-thing 4x" (double-cons one-thing (double-cons one-thing another-thing))) (quadruple-cons 'um '(huh?)) Function arguments are LOCAL variables (setq shoes 'nikes) (defun run (shoes) (print (append '(i think i will take a trot in my) (list shoes))) (setq shoes (append '(old beat-up) (list shoes))) (print (append '(i think i will take a trot in my) shoes))) (run shoes) (print 'foo) (defun run (shoes) ;; this version returns '(I RAN) (print (append '(i think i will take a trot in my) (list shoes))) (setq shoes (append '(old beat-up) (list shoes))) (print (append '(i think i will take a trot in my) shoes)) '(i ran)) (run shoes) shoes the nth function returns an element of a list by number (setq animals '(giraffe dog dinosaur bug big-bug big-hairy-bug)) (nth 0 animals) (nth 1 animals) (nth 2 animals) (nth 3 animals) (nth 4 animals) (nth 5 animals) (nth 6 animals) the length function returns the number of elements in a list (length animals) (length '(the (deeper (you (go (the (nuller (you (get))))))))) here's a function to return a random element of a list (defun random-elt (choices) "returns one element of the list of choices at random" (nth (random (length choices)) choices)) (random-elt animals) (random-elt animals) this returns a random element as a singleton list (defun one-of (set) "picks one element of the set and returns it in a list" (list (random-elt set))) (one-of '(how are you doing today?)) From Norvig Chapter 2 A Grammar for a (miniscule) Subset of English: Sentence => Noun-Phrase + Verb-Phrase Noun-Phrase => Article + Noun Verb-Phrase => Verb + Noun-Phrase Article => the, a, ... Noun => man, ball, woman, table ... Verb => hit, took, saw, liked ... The grammar can be used to generate sentences: To get a Sentence, append a Noun-Phrase and a Verb-Phrase To get a Noun-Phrase, append an Article and a Noun Choose "the" for the Article Choose "man" for the Noun The resulting Noun-Phrase is "the man" To get a Verb-Phrase, append a Verb and a Noun-Phrase Choose "hit" for the Verb [etc.] The grammar can be used as the basis of the following Lisp functions: (defun sentence () "generates and returns a sentence as a list of atoms" (append (noun-phrase) (verb-phrase))) (defun noun-phrase () "generates and returns a noun-phrase as a list of atoms" (append (article) (noun))) (defun verb-phrase () "generates and returns a verb-phrase as a list of atoms" (append (verb) (noun-phrase))) (defun article () "generates and returns an article as an atom in a list" (one-of '(the a))) (defun noun () "generates and returns a noun as an atom in a list" (one-of '(man ball woman table))) (defun verb () "generates and returns a noun as an atom in a list" (one-of '(hit took saw liked))) (sentence) (sentence) (sentence) (noun-phrase) (verb-phrase) (noun) (verb) (trace sentence noun-phrase verb-phrase article noun verb) (sentence) (untrace) Here's a function using COND that returns an atom indicating whether its argument is even or odd (or not a number). (defun even-or-odd? (n) "returns 'even if n is even, 'odd if n is odd, and 'neither if n is not an integer" (cond ((not (integerp n)) 'neither) ((evenp n) 'even) ((oddp n) 'odd))) (even-or-odd? 24) (even-or-odd? 25) (even-or-odd? '(swahili)) Here's a function called lat?, that takes one argument and returns t if that argument is a list of atoms. (defun lat? (l) "Returns t if the argument is a list of atoms, nil otherwise" (cond ((null l) t) ((atom (car l)) (lat? (cdr l))) (t nil))) (lat? '(remember the alamo)) (lat? '(did you remember (to floss?))) (lat? long-list) (lat? 12) (defun lat? (l) "Returns t if the argument is a list of atoms, nil otherwise" (cond ((not (listp l)) nil) ((null l) t) ((atom (car l)) (lat? (cdr l))) (t nil))) (lat? 12) The following member? function checks to see if its first argument occurs in its second: (defun member? (a lat) "Returns t if a occurs in lat, nil otherwise" (cond ((null lat) nil) (t (or (equalp (car lat) a) (member? a (cdr lat)))))) (setq five-colleges '(amherst umass hampshire smith mount-holyoke)) (member? 'hampshire five-colleges) (member? 'oberlin five-colleges) Common Lisp includes a function called MEMBER that does a similar thing. Note, however, that it returns the matching cdr rather than t: (member 'hampshire five-colleges) (member 'oberlin five-colleges) Note that MEMBER compares using EQ, not EQUALP. For example: (member '(nest) '(a hornet in a hornet (nest) is to be avoided)) (member? '(nest) '(a hornet in a hornet (nest) is to be avoided)) We can get MEMBER to match using equalp by providing a keyword argument (details on this another day...) (member '(nest) '(a hornet in a hornet (nest) is to be avoided) :test #'equalp) Here's a generalization of double-cons and quadruple-cons defined above: (defun multi-cons (one-thing another-thing n) "Returns the result of consing one-thing onto another-thing n times" (cond ((equalp n 0) another-thing) (t (cons one-thing (multi-cons one-thing another-thing (- n 1)))))) (multi-cons 'hip '(hooray) 5) Lisp control structures and function manipulation Global and local variables Global, dynamically scoped variables can be created with defvar or defparameter DEFVAR variable-name &optional initial-value documentation [Macro] proclaims variable-name to be a special variable, optionally sets it to the value of initial-value, and returns variable-name. If initial-value is given, variable-name is initialized to the result of evaluating it unless variable-name already has a value. If initial-name is not used, it is not evaluated. The macro defvar only has an effect the first time it is called on a symbol. Documentation may be provided as a string. DEFPARAMETER variable-name initial-value &optional documentation [Macro] proclaims variable-name to be a special variable, sets it to the value of evaluating initial-value, a form, and returns variable-name. Documentation may be provided as a string. Globals are conventionally written with surrounding * characters: (defvar *world-state* '((clear block-a) (on block-a table))) (defparameter *depth-limit* 10 "The maximum depth to which we will search") Note: Subsequent defvars for a previously defvar'd variable are ignored. Subsequent defparameters act as setq's. The LET special form is used to create local variables. (let ((foo 2) (bar 3)) (+ foo bar)) LET ({variable | (variable value) }*) {declaration}* {form}* [Special Form] creates a binding for each variable (in parallel) and evaluates forms in the resulting environment. Returns the value of the last form. (setq laadeedaa 'hihohiho) (let ((laadeedaa 'feefifofum)) (list laadeedaa laadeedaa laadeedaa)) laadeedaa Note that the initializations in a LET are performed "in parallel" -- you may not rely on the earlier ones being performed before the later ones. If you want sequential initialization behavior, use LET*: (let* ((foo 2) (bar (+ foo 3))) (+ foo bar)) Recursion and control structures A closer look at recursive programming: Wilensky p. 89: ...we have the collowing components to recursive programming: (1) Breaking down the task at hand into a form that involves simpler versions of the same task. (2) Specifying a way to combine the simpler versions of the task to solve the original problem. (3) Identifying the "grounding" situations in which the task can be accomplished directly. (4) Specifying checks for these grounding cases that will be examined before recursive steps are taken. (defun factorial (n) "returns the factorial of n" (cond ((<= n 1) 1) (t (* n (factorial (- n 1)))))) (factorial 5) (trace factorial) (factorial 5) Calling (FACTORIAL 5) Calling (FACTORIAL 4) Calling (FACTORIAL 3) Calling (FACTORIAL 2) Calling (FACTORIAL 1) FACTORIAL returned 1 FACTORIAL returned 2 FACTORIAL returned 6 FACTORIAL returned 24 FACTORIAL returned 120 ;; here's another version (defun factorial (n) "returns the factorial of n" (cond ((zerop n) 1) (t (* n (factorial (- n 1)))))) (factorial 5) The IF special form is a special case of COND: IF testform thenform [elseform] [Special Form] evaluates testform. If the result is true, evaluates thenform and returns the result; if the result is nil, evaluates elseform and returns the result. (if (> 100 23) 'sure-is 'sure-aint) (if (member 'bog '(blig blog bog bumper)) (* 99 99) (sqrt -1)) (if (member 'fog '(blig blog bog bumper)) (* 99 99) (sqrt -1)) Note that the thenform and the elseform are both restricted to being single forms. In contrast, you can specify any number of forms in a cond clause: (setq temperature 8) (cond ((< temperature 32) (print '(yowch -- it is cold!)) (print '(i will play god and change that!)) (setq temperature 78)) (t (print '(well i guess it is not so bad)) (print '(where do you think we are? hawaii?)))) If you want multiple forms in an IF you can use a PROGN: PROGN {form}* [Special Form] evaluates each form in order, left to right. The values of all forms but the last are discarded; the value of the last form is returned. (if (< temperature 32) (progn (print '(yowch -- it is cold!)) (print '(i will play god and change that!)) (setq temperature 78)) (progn (print '(well i guess it is not so bad)) (print '(where do you think we are? hawaii?)))) Using IF we can write a simpler version of factorial: (defun factorial (n) "returns the factorial of n" (if (zerop n) 1 (* n (factorial (- n 1))))) (factorial 5) ;; here's a recursive length function (defun my-length (list) "returns the length of list" (if (null list) 0 (+ 1 (my-length (cdr list))))) (my-length '(let it snow let it snow let it AAAARRRRRGGGGGHHHH!!!!)) Sometimes iteration seems more natural. Common Lisp provides many iteration constructs. DOTIMES (var countform [resultform]) {declaration}* {tag | statement}* [Macro] executes forms countform times. On successive executions, var is bound to the integers between zero and countform. Upon completion, resultform is evaluated, and the value is returned. If resultform is omitted, the result is nil. (dotimes (n 20 'spumoni) (print n)) Here was our recursive function multicons: (defun multi-cons (one-thing another-thing n) "Returns the result of consing one-thing onto another-thing n times" (cond ((equalp n 0) another-thing) (t (cons one-thing (multi-cons one-thing another-thing (- n 1)))))) (multi-cons 'hip '(hooray) 5) Here's a version using dotimes: (defun multi-cons (one-thing another-thing n) "Returns the result of consing one-thing onto another-thing n times" (dotimes (count n) (setq another-thing (cons one-thing another-thing))) another-thing) (multi-cons 'hip '(hooray) 5) DOLIST (var listform [resultform]) {declaration}* {tag | statement}* [Macro] evaluates listform, which produces a list, and executes the body once for every element in the list. On each iteration, var is bound to successive elements of the list. Upon completion, resultform is evaluated, and the value is returned. If resultform is omitted, the result is nil. (defun greet (people) "prints greetings for all of the people listed." (dolist (person people) (print (append '(so nice to see you) (list person))))) (setq guests '(sally booboo mr-pajamas ms-potato-head)) (greet guests) Tthe PROG macro allows various kinds of iteration, but it should be avoided -- it violates normal "structured programming" rules. PROG ({var | (var [init])}*) {declaration}* {tag | statement}* [Macro] binds the vars to the values of the inits in parallel (or to nil for vars with no corresponding init), and then executes the statements. The entire prog form is implicitly surrounded by a block named nil (so that return may be used at any time to exit from the construct), and the body is a tagbody. prog returns nil. (defun prehistory (character) (prog ((name character) (husband-name nil) (dinosaur-name nil)) name-print (print name) (if husband-name (print (append '(has husband) (list husband-name)))) (if husband-name (go dinosaur) (go check-husband)) check-husband (if (equalp name 'wilma) (setq husband-name 'fred)) (if (equalp name 'betty) (setq husband-name 'barney)) (if (null husband-name) (return 'no-husband)) (go name-print) dinosaur (if (equalp name 'wilma) (setq dinosaur-name 'dino)) (if dinosaur-name (print (append '(has dinosaur) (list dinosaur-name))) (return 'no-dinosaur)) (return 'yabadabadoo!))) (prehistory 'wilma) (prehistory 'betty) (prehistory 'francine) DO is an extremely general, powerful tool for iteration DO ({var | (var [init [step]])}*) (end-test {result}*) {declaration}* {tag | statement}* [Macro] at the beginning of each iteration, evaluates all the init forms (before any var is bound), then binds each var to the value of its init . Then evaluates end-test; if the result is nil, execution proceeds with the body of the form. If the result is non-nil, the result forms are evaluated as an implicit progn and the value of the last result form is returned. At the beginning of the second and subsequent iterations, all step forms are evaluated, then all variables are updated. (do ((i 1 (+ i 1))) ((> i 10) 'got-to-ten) (print i)) Common Lisp provides an additional iteration mechanism via so-called mapping functions. (defun smell-test (thing) "returns either good, bad, or lousy, depending on how thing smells. By default, most things smell bad." (cond ((member thing '(rose daisy chocolate)) 'good) ((member thing '(dirty-socks dirty-politics toe-cheese)) 'lousy) (t 'bad))) (mapcar #'smell-test '(rose roast cheese toe-cheese chocolate)) Function cell vs. value cell (defun figs (a b) '(yum yum)) (setq figs 5) (figs 2 3) figs (symbol-function 'figs) (function figs) #'figs Functions as first-class objects Higher order functions (defun double (x) (list x x)) (double 3) (funcall 'double 3) (funcall #'double 3) (apply #'double '(3)) (setq list-o-numbers '(22 44 66 88)) (apply #'+ list-o-numbers) (setq my-function #'double) (funcall my-function 3) (double '(a b)) MAPCAR function list &rest more-lists [Function] applies function to the car of list and more-lists, then to the cadr, and so on. The results are collected into a list, which is returned. If the lists are not all the same length, the iteration terminates when the shortest list runs out. function can be only of type symbol or function. (setq x '(a b c d e f g h i j k l m n o p q r)) (mapcar #'double x) (setq y '(8 (99 100) hello)) (mapcar #'double y) (setq x (mapcar #'double x)) (defun halve (n) (/ n 2.0)) (mapcar #'halve '( 1 2 3 4)) (mapcar #'+ '(1 2 3) '(8 9 10)) (mapcar #'+ '(1 2 3) '(8 9)) (setq x '( 1 2 3)) (apply #'+ x) (+ 1 2 3) (eval (cons '+ x)) (defun mappend (fn l) (apply #'append (mapcar fn l))) (mapcar #'double x) (mappend #'double x) (mapcar #'double '(a b c)) (mappend #'double '(a b c)) You can always use a lambda expression instead of a named function ((lambda (x) (+ x x)) 23) ((lambda (a b) (list a a b 'and 'furthermore b)) 'spam 'clam) Lambda expressions are particularly handy in conjunction with mapping functions (mapcar #'(lambda (x) (+ x 100)) '(2 4 6 8 10)) Here we can get the effect of a TRIPLE function without having defined one before (mapcar #'(lambda (thing) (list thing thing thing)) '(a b c)) (mappend #'(lambda (thing) (list thing thing thing)) '(a b c)) mapc is a version of mapcar that doesn't bother to produce a return value. It just returns its second argument. (mapc #'(lambda (n) (print (* n 2))) '(1 2 3 4)) maplist applies a function to successive CDRs of a list, rather than to successive elements (maplist #'print '(doe a dear a female dear)) (maplist #'(lambda (numbers) (apply #'+ numbers)) '(1 2 3 4 5 6 7 8 9 10)) mapl is the same but, like mapc, it doesn't bother with putting together a return value (mapl #'print '(doe a dear a female dear)) (maplist #'print '(doe a dear a female dear))