;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 0. Syntax;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; General form.;; Lisp has two fundamental pieces of syntax: the ATOM and the;; S-expression. Typically, grouped S-expressions are called `forms`.10; an atom; it evaluates to itself:THING;Another atom; evaluating to the symbol :thing.t; another atom, denoting true.(+1234); an s-expression'(4:foot);another one;;; Comments;; Single line comments start with a semicolon; use two for normal;; comments, three for section comments, and four for file-level;; comments.#| Block comments
can span multiple lines and...
#|
they can be nested!
|#
|#;;; Environment.;; A variety of implementations exist; most are;; standard-conformant. CLISP is a good starting one.;; Libraries are managed through Quicklisp.org's Quicklisp system.;; Common Lisp is usually developed with a text editor and a REPL;; (Read Evaluate Print Loop) running at the same time. The REPL;; allows for interactive exploration of the program as it is "live";; in the system.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1. Primitive Datatypes and Operators;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Symbols'foo; => FOO Notice that the symbol is upper-cased automatically.;; Intern manually creates a symbol from a string.(intern"AAAA"); => AAAA(intern"aaa"); => |aaa|;;; Numbers9999999999999999999999; integers#b111; binary => 7#o111; octal => 73#x111; hexadecimal => 2733.14159s0; single3.14159d0; double1/2; ratios#C(12); complex numbers;; Function application is written (f x y z ...);; where f is a function and x, y, z, ... are operands;; If you want to create a literal list of data, use ' to stop it from;; being evaluated - literally, "quote" the data.'(+12); => (+ 1 2);; You can also call a function manually:(funcall#'+123); => 6;; Some arithmetic operations(+11); => 2(-81); => 7(*102); => 20(expt23); => 8(mod52); => 1(/355); => 7(/13); => 1/3(+#C(12)#C(6-4)); => #C(7 -2);;; Booleanst; for true (any not-nil value is true)nil; for false - and the empty list(notnil); => t(and0t); => t(or0nil); => 0;;; Characters#\A; => #\A#\λ; => #\GREEK_SMALL_LETTER_LAMDA#\u03BB; => #\GREEK_SMALL_LETTER_LAMDA;;; Strings are fixed-length arrays of characters."Hello, world!""Benjamin \"Bugsy\" Siegel"; backslash is an escaping character;; Strings can be concatenated too!(concatenate'string"Hello ""world!"); => "Hello world!";; A string can be treated like a sequence of characters(elt"Apple"0); => #\A;; format can be used to format strings:(formatnil"~a can be ~a""strings""formatted");; Printing is pretty easy; ~% is the format specifier for newline.(formatt"Common Lisp is groovy. Dude.~%");;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2. Variables;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; You can create a global (dynamically scoped) using defparameter;; a variable name can use any character except: ()",'`;#|\;; Dynamically scoped variables should have earmuffs in their name!(defparameter*some-var*5)*some-var*; => 5;; You can also use unicode characters.(defparameter*AΛB*nil);; Accessing a previously unbound variable is an;; undefined behavior (but possible). Don't do it.;; Local binding: `me` is bound to "dance with you" only within the;; (let ...). Let always returns the value of the last `form` in the;; let form.(let((me"dance with you"))me);; => "dance with you";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3. Structs and Collections;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Structs(defstructdognamebreedage)(defparameter*rover*(make-dog:name"rover":breed"collie":age5))*rover*; => #S(DOG :NAME "rover" :BREED "collie" :AGE 5)(dog-p*rover*); => t ;; ewww)(dog-name*rover*); => "rover";; Dog-p, make-dog, and dog-name are all created by defstruct!;;; Pairs;; `cons' constructs pairs, `car' and `cdr' extract the first;; and second elements(cons'SUBJECT'VERB); => '(SUBJECT . VERB)(car(cons'SUBJECT'VERB)); => SUBJECT(cdr(cons'SUBJECT'VERB)); => VERB;;; Lists;; Lists are linked-list data structures, made of `cons' pairs and end;; with a `nil' (or '()) to mark the end of the list(cons1(cons2(cons3nil))); => '(1 2 3);; `list' is a convenience variadic constructor for lists(list123); => '(1 2 3);; and a quote can also be used for a literal list value'(123); => '(1 2 3);; Can still use `cons' to add an item to the beginning of a list(cons4'(123)); => '(4 1 2 3);; Use `append' to - surprisingly - append lists together(append'(12)'(34)); => '(1 2 3 4);; Or use concatenate -(concatenate'list'(12)'(34));; Lists are a very central type, so there is a wide variety of functionality for;; them, a few examples:(mapcar#'1+'(123)); => '(2 3 4)(mapcar#'+'(123)'(102030)); => '(11 22 33)(remove-if-not#'evenp'(1234)); => '(2 4)(every#'evenp'(1234)); => nil(some#'oddp'(1234)); => T(butlast'(subjectverbobject)); => (SUBJECT VERB);;; Vectors;; Vector's literals are fixed-length arrays#(123); => #(1 2 3);; Use concatenate to add vectors together(concatenate'vector#(123)#(456)); => #(1 2 3 4 5 6);;; Arrays;; Both vectors and strings are special-cases of arrays.;; 2D arrays(make-array(list22));; (make-array '(2 2)) works as well.; => #2A((0 0) (0 0))(make-array(list222)); => #3A(((0 0) (0 0)) ((0 0) (0 0)));; Caution- the default initial values are;; implementation-defined. Here's how to define them:(make-array'(2):initial-element'unset); => #(UNSET UNSET);; And, to access the element at 1,1,1 -(aref(make-array(list222))111); => 0;;; Adjustable vectors;; Adjustable vectors have the same printed representation;; as fixed-length vector's literals.(defparameter*adjvec*(make-array'(3):initial-contents'(123):adjustablet:fill-pointert))*adjvec*; => #(1 2 3);; Adding new element:(vector-push-extend4*adjvec*); => 3*adjvec*; => #(1 2 3 4);;; Naively, sets are just lists:(set-difference'(1234)'(4567)); => (3 2 1)(intersection'(1234)'(4567)); => 4(union'(1234)'(4567)); => (3 2 1 4 5 6 7)(adjoin4'(1234)); => (1 2 3 4);; But you'll want to use a better data structure than a linked list;; for performant work!;;; Dictionaries are implemented as hash tables.;; Create a hash table(defparameter*m*(make-hash-table));; set a value(setf(gethash'a*m*)1);; Retrieve a value(gethash'a*m*); => 1, t;; Detail - Common Lisp has multiple return values possible. gethash;; returns t in the second value if anything was found, and nil if;; not.;; Retrieving a non-present value returns nil(gethash'd*m*);=> nil, nil;; You can provide a default value for missing keys(gethash'd*m*:not-found); => :NOT-FOUND;; Let's handle the multiple return values here in code.(multiple-value-bind(ab)(gethash'd*m*)(listab)); => (NIL NIL)(multiple-value-bind(ab)(gethash'a*m*)(listab)); => (1 T);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3. Functions;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Use `lambda' to create anonymous functions.;; A function always returns the value of its last expression.;; The exact printable representation of a function will vary...(lambda()"Hello World"); => #<FUNCTION (LAMBDA ()) {1004E7818B}>;; Use funcall to call lambda functions(funcall(lambda()"Hello World")); => "Hello World";; Or Apply(apply(lambda()"Hello World")nil); => "Hello World";; De-anonymize the function(defunhello-world()"Hello World")(hello-world); => "Hello World";; The () in the above is the list of arguments for the function(defunhello(name)(formatnil"Hello, ~a "name))(hello"Steve"); => "Hello, Steve";; Functions can have optional arguments; they default to nil(defunhello(name&optionalfrom)(iffrom(formatt"Hello, ~a, from ~a"namefrom)(formatt"Hello, ~a"name)))(hello"Jim""Alpacas");; => Hello, Jim, from Alpacas;; And the defaults can be set...(defunhello(name&optional(from"The world"))(formatt"Hello, ~a, from ~a"namefrom))(hello"Steve"); => Hello, Steve, from The world(hello"Steve""the alpacas"); => Hello, Steve, from the alpacas;; And of course, keywords are allowed as well... usually more;; flexible than &optional.(defungeneralized-greeter(name&key(from"the world")(honorific"Mx"))(formatt"Hello, ~a ~a, from ~a"honorificnamefrom))(generalized-greeter"Jim"); => Hello, Mx Jim, from the world(generalized-greeter"Jim":from"the alpacas you met last summer":honorific"Mr"); => Hello, Mr Jim, from the alpacas you met last summer;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4. Equality;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Common Lisp has a sophisticated equality system. A couple are covered here.;; for numbers use `='(=33.0); => t(=21); => nil;; for object identity (approximately) use `eql`(eql33); => t(eql33.0); => nil(eql(list3)(list3)); => nil;; for lists, strings, and bit-vectors use `equal'(equal(list'a'b)(list'a'b)); => t(equal(list'a'b)(list'b'a)); => nil;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 5. Control Flow;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Conditionals(ift; test expression"this is true"; then expression"this is false"); else expression; => "this is true";; In conditionals, all non-nil values are treated as true(member'Groucho'(HarpoGrouchoZeppo)); => '(GROUCHO ZEPPO)(if(member'Groucho'(HarpoGrouchoZeppo))'yep'nope); => 'YEP;; `cond' chains a series of tests to select a result(cond((>22)(error"wrong!"))((<22)(error"wrong again!"))(t'ok)); => 'OK;; Typecase switches on the type of the value(typecase1(string:string)(integer:int)); => :int;;; Iteration;; Of course recursion is supported:(defunwalker(n)(if(zeropn):walked(walker(1-n))))(walker5); => :walked;; Most of the time, we use DOLIST or LOOP(dolist(i'(1234))(formatt"~a"i)); => 1234(loopforifrom0below10collecti); => (0 1 2 3 4 5 6 7 8 9);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 6. Mutation;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Use `setf' to assign a new value to an existing variable. This was;; demonstrated earlier in the hash table example.(let((variable10))(setfvariable2)); => 2;; Good Lisp style is to minimize destructive functions and to avoid;; mutation when reasonable.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 7. Classes and Objects;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; No more Animal classes, let's have Human-Powered Mechanical;; Conveyances.(defclasshuman-powered-conveyance()((velocity:accessorvelocity:initarg:velocity)(average-efficiency:accessoraverage-efficiency:initarg:average-efficiency))(:documentation"A human powered conveyance"));; defclass, followed by name, followed by the superclass list,;; followed by slot list, followed by optional qualities such as;; :documentation.;; When no superclass list is set, the empty list defaults to the;; standard-object class. This *can* be changed, but not until you;; know what you're doing. Look up the Art of the Metaobject Protocol;; for more information.(defclassbicycle(human-powered-conveyance)((wheel-size:accessorwheel-size:initarg:wheel-size:documentation"Diameter of the wheel.")(height:accessorheight:initarg:height)))(defclassrecumbent(bicycle)((chain-type:accessorchain-type:initarg:chain-type)))(defclassunicycle(human-powered-conveyance)nil)(defclasscanoe(human-powered-conveyance)((number-of-rowers:accessornumber-of-rowers:initarg:number-of-rowers)));; Calling DESCRIBE on the human-powered-conveyance class in the REPL gives:(describe'human-powered-conveyance); COMMON-LISP-USER::HUMAN-POWERED-CONVEYANCE; [symbol];; HUMAN-POWERED-CONVEYANCE names the standard-class #<STANDARD-CLASS; HUMAN-POWERED-CONVEYANCE>:; Documentation:; A human powered conveyance; Direct superclasses: STANDARD-OBJECT; Direct subclasses: UNICYCLE, BICYCLE, CANOE; Not yet finalized.; Direct slots:; VELOCITY; Readers: VELOCITY; Writers: (SETF VELOCITY); AVERAGE-EFFICIENCY; Readers: AVERAGE-EFFICIENCY; Writers: (SETF AVERAGE-EFFICIENCY);; Note the reflective behavior available to you! Common Lisp is;; designed to be an interactive system;; To define a method, let's find out what our circumference of the;; bike wheel turns out to be using the equation: C = d * pi(defmethodcircumference((objectbicycle))(*pi(wheel-sizeobject)));; pi is defined in Lisp already for us!;; Let's suppose we find out that the efficiency value of the number;; of rowers in a canoe is roughly logarithmic. This should probably be set;; in the constructor/initializer.;; Here's how to initialize your instance after Common Lisp gets done;; constructing it:(defmethodinitialize-instance:after((objectcanoe)&restargs)(setf(average-efficiencyobject)(log(1+(number-of-rowersobject)))));; Then to construct an instance and check the average efficiency...(average-efficiency(make-instance'canoe:number-of-rowers15)); => 2.7725887;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 8. Macros;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Macros let you extend the syntax of the language;; Common Lisp doesn't come with a WHILE loop- let's add one.;; If we obey our assembler instincts, we wind up with:(defmacrowhile(condition&bodybody)"While `condition` is true, `body` is executed.
`condition` is tested prior to each execution of `body`"(let((block-name(gensym))(done(gensym)))`(tagbody,block-name(unless,condition(go,done))(progn,@body)(go,block-name),done)));; Let's look at the high-level version of this:(defmacrowhile(condition&bodybody)"While `condition` is true, `body` is executed.
`condition` is tested prior to each execution of `body`"`(loopwhile,conditiondo(progn,@body)));; However, with a modern compiler, this is not required; the LOOP;; form compiles equally well and is easier to read.;; Note that ``` is used, as well as `,` and `@`. ``` is a quote-type operator;; known as quasiquote; it allows the use of `,` . `,` allows "unquoting";; variables. @ interpolates lists.;; Gensym creates a unique symbol guaranteed to not exist elsewhere in;; the system. This is because macros are expanded at compile time and;; variables declared in the macro can collide with variables used in;; regular code.;; See Practical Common Lisp for more information on macros.