mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-12-23 17:41:41 +00:00
[common-lisp/en]: clean up and add more information
This commit is contained in:
parent
9f33f260dc
commit
6968c57248
@ -4,82 +4,91 @@ language: "Common Lisp"
|
|||||||
filename: commonlisp.lisp
|
filename: commonlisp.lisp
|
||||||
contributors:
|
contributors:
|
||||||
- ["Paul Nathan", "https://github.com/pnathan"]
|
- ["Paul Nathan", "https://github.com/pnathan"]
|
||||||
|
- ["Rommel Martinez", "https://ebzzry.io"]
|
||||||
---
|
---
|
||||||
|
|
||||||
ANSI Common Lisp is a general purpose, multi-paradigm programming
|
Common Lisp is a general-purpose, multi-paradigm programming language suited for a wide variety of
|
||||||
language suited for a wide variety of industry applications. It is
|
industry applications. It is frequently referred to as a programmable programming language.
|
||||||
frequently referred to as a programmable programming language.
|
|
||||||
|
|
||||||
The classic starting point is [Practical Common Lisp and freely available.](http://www.gigamonkeys.com/book/)
|
The classic starting point is [Practical Common Lisp](http://www.gigamonkeys.com/book/). Another
|
||||||
|
popular and recent book is [Land of Lisp](http://landoflisp.com/). A new book about best practices,
|
||||||
Another popular and recent book is
|
[Common Lisp Recipes](http://weitz.de/cl-recipes/), was recently published.
|
||||||
[Land of Lisp](http://landoflisp.com/).
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```common_lisp
|
```common_lisp
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;-----------------------------------------------------------------------------
|
||||||
;;; 0. Syntax
|
;;; 0. Syntax
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;-----------------------------------------------------------------------------
|
||||||
|
|
||||||
;;; General form.
|
;;; General form
|
||||||
|
|
||||||
;; Lisp has two fundamental pieces of syntax: the ATOM and the
|
;;; CL has two fundamental pieces of syntax: ATOM and S-EXPRESSION.
|
||||||
;; S-expression. Typically, grouped S-expressions are called `forms`.
|
;;; Typically, grouped S-expressions are called `forms`.
|
||||||
|
|
||||||
10 ; an atom; it evaluates to itself
|
10 ; an atom; it evaluates to itself
|
||||||
|
:thing ; another atom; evaluating to the symbol :thing
|
||||||
:THING ;Another atom; evaluating to the symbol :thing.
|
t ; another atom, denoting true
|
||||||
|
|
||||||
t ; another atom, denoting true.
|
|
||||||
|
|
||||||
(+ 1 2 3 4) ; an s-expression
|
(+ 1 2 3 4) ; an s-expression
|
||||||
|
'(4 :foo t) ; another s-expression
|
||||||
'(4 :foo t) ;another one
|
|
||||||
|
|
||||||
|
|
||||||
;;; Comments
|
;;; Comments
|
||||||
|
|
||||||
;; Single line comments start with a semicolon; use two for normal
|
;;; Single-line comments start with a semicolon; use four for file-level
|
||||||
;; comments, three for section comments, and four for file-level
|
;;; comments, three for section descriptions, two inside definitions, and one
|
||||||
;; comments.
|
;;; for single lines. For example,
|
||||||
|
|
||||||
#| Block comments
|
;;;; life.lisp
|
||||||
can span multiple lines and...
|
|
||||||
|
;;; Foo bar baz, because quu quux. Optimized for maximum krakaboom and umph.
|
||||||
|
;;; Needed by the function LINULUKO.
|
||||||
|
|
||||||
|
(defun meaning (life)
|
||||||
|
"Return the computed meaning of LIFE"
|
||||||
|
(let ((meh "abc"))
|
||||||
|
;; Invoke krakaboom
|
||||||
|
(loop :for x :across meh
|
||||||
|
:collect x))) ; store values into x, then return it
|
||||||
|
|
||||||
|
;;; Block comments, on the other hand, allow for free-form comments. They are
|
||||||
|
;;; delimited with #| and |#
|
||||||
|
|
||||||
|
#| This is a block comment which
|
||||||
|
can span multiple lines and
|
||||||
#|
|
#|
|
||||||
they can be nested!
|
they can be nested!
|
||||||
|#
|
|#
|
||||||
|#
|
|#
|
||||||
|
|
||||||
;;; Environment.
|
|
||||||
|
|
||||||
;; A variety of implementations exist; most are
|
;;; Environment
|
||||||
;; standard-conformant. CLISP is a good starting one.
|
|
||||||
|
|
||||||
;; Libraries are managed through Quicklisp.org's Quicklisp system.
|
;;; A variety of implementations exist; most are standards-conformant. SBCL
|
||||||
|
;;; is a good starting point. Third party libraries can be easily installed with
|
||||||
|
;;; Quicklisp
|
||||||
|
|
||||||
;; Common Lisp is usually developed with a text editor and a REPL
|
;;; CL is usually developed with a text editor and a Real Eval Print
|
||||||
;; (Read Evaluate Print Loop) running at the same time. The REPL
|
;;; Loop (REPL) running at the same time. The REPL allows for interactive
|
||||||
;; allows for interactive exploration of the program as it is "live"
|
;;; exploration of the program while it is running "live".
|
||||||
;; in the system.
|
|
||||||
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;-----------------------------------------------------------------------------
|
||||||
;;; 1. Primitive Datatypes and Operators
|
;;; 1. Primitive datatypes and operators
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;-----------------------------------------------------------------------------
|
||||||
|
|
||||||
;;; Symbols
|
;;; Symbols
|
||||||
|
|
||||||
'foo ; => FOO Notice that the symbol is upper-cased automatically.
|
'foo ; => FOO Notice that the symbol is upper-cased automatically.
|
||||||
|
|
||||||
;; Intern manually creates a symbol from a string.
|
;;; INTERN manually creates a symbol from a string.
|
||||||
|
|
||||||
(intern "AAAA") ; => AAAA
|
(intern "AAAA") ; => AAAA
|
||||||
|
|
||||||
(intern "aaa") ; => |aaa|
|
(intern "aaa") ; => |aaa|
|
||||||
|
|
||||||
;;; Numbers
|
;;; Numbers
|
||||||
|
|
||||||
9999999999999999999999 ; integers
|
9999999999999999999999 ; integers
|
||||||
#b111 ; binary => 7
|
#b111 ; binary => 7
|
||||||
#o111 ; octal => 73
|
#o111 ; octal => 73
|
||||||
@ -89,15 +98,24 @@ t ; another atom, denoting true.
|
|||||||
1/2 ; ratios
|
1/2 ; ratios
|
||||||
#C(1 2) ; complex numbers
|
#C(1 2) ; complex numbers
|
||||||
|
|
||||||
|
;;; Function application are written as (f x y z ...) where f is a function and
|
||||||
|
;;; x, y, z, ... are the arguments.
|
||||||
|
|
||||||
|
(+ 1 2) ; => 3
|
||||||
|
|
||||||
|
;;; If you want to create literal data, use QUOTE to prevent it from being
|
||||||
|
;;; evaluated
|
||||||
|
|
||||||
|
(quote (+ 1 2)) ; => (+ 1 2)
|
||||||
|
(quote a) ; => A
|
||||||
|
|
||||||
|
;;; The shorthand for QUOTE is '
|
||||||
|
|
||||||
;; 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.
|
|
||||||
'(+ 1 2) ; => (+ 1 2)
|
'(+ 1 2) ; => (+ 1 2)
|
||||||
;; You can also call a function manually:
|
'a ; => A
|
||||||
(funcall #'+ 1 2 3) ; => 6
|
|
||||||
;; Some arithmetic operations
|
;;; Basic arithmetic operations
|
||||||
|
|
||||||
(+ 1 1) ; => 2
|
(+ 1 1) ; => 2
|
||||||
(- 8 1) ; => 7
|
(- 8 1) ; => 7
|
||||||
(* 10 2) ; => 20
|
(* 10 2) ; => 20
|
||||||
@ -108,294 +126,334 @@ t ; another atom, denoting true.
|
|||||||
(+ #C(1 2) #C(6 -4)) ; => #C(7 -2)
|
(+ #C(1 2) #C(6 -4)) ; => #C(7 -2)
|
||||||
|
|
||||||
;;; Booleans
|
;;; Booleans
|
||||||
t ; for true (any not-nil value is true)
|
|
||||||
nil ; for false - and the empty list
|
t ; true; any non-NIL value is true
|
||||||
(not nil) ; => t
|
nil ; false; also, the empty list: ()
|
||||||
(and 0 t) ; => t
|
(not nil) ; => T
|
||||||
|
(and 0 t) ; => T
|
||||||
(or 0 nil) ; => 0
|
(or 0 nil) ; => 0
|
||||||
|
|
||||||
;;; Characters
|
;;; Characters
|
||||||
|
|
||||||
#\A ; => #\A
|
#\A ; => #\A
|
||||||
#\λ ; => #\GREEK_SMALL_LETTER_LAMDA
|
#\λ ; => #\GREEK_SMALL_LETTER_LAMDA
|
||||||
#\u03BB ; => #\GREEK_SMALL_LETTER_LAMDA
|
#\u03BB ; => #\GREEK_SMALL_LETTER_LAMDA
|
||||||
|
|
||||||
;;; Strings are fixed-length arrays of characters.
|
;;; Strings are fixed-length arrays of characters
|
||||||
|
|
||||||
"Hello, world!"
|
"Hello, world!"
|
||||||
"Benjamin \"Bugsy\" Siegel" ; backslash is an escaping character
|
"Benjamin \"Bugsy\" Siegel" ; backslash is an escaping character
|
||||||
|
|
||||||
;; Strings can be concatenated too!
|
;;; Strings can be concatenated
|
||||||
(concatenate 'string "Hello " "world!") ; => "Hello world!"
|
|
||||||
|
(concatenate 'string "Hello, " "world!") ; => "Hello, world!"
|
||||||
|
|
||||||
|
;;; A string can be treated like a sequence of characters
|
||||||
|
|
||||||
;; A string can be treated like a sequence of characters
|
|
||||||
(elt "Apple" 0) ; => #\A
|
(elt "Apple" 0) ; => #\A
|
||||||
|
|
||||||
;; format can be used to format strings:
|
;;; FORMAT is used to create formatted output, which ranges from simple string
|
||||||
(format nil "~a can be ~a" "strings" "formatted")
|
;;; interpolation to loops and conditionals. The first argument to FORMAT
|
||||||
|
;;; determines where will the formatted string go. If it is NIL, FORMAT
|
||||||
|
;;; simply returns the formatted string as a value; if it is T, FORMAT outputs
|
||||||
|
;;; to the standard output, usually the screen, then it returns NIL.
|
||||||
|
|
||||||
;; Printing is pretty easy; ~% is the format specifier for newline.
|
(format nil "~A, ~A!" "Hello" "world") ; => "Hello, world!"
|
||||||
(format t "Common Lisp is groovy. Dude.~%")
|
(format t "~A, ~A!" "Hello" "world") ; => NIL
|
||||||
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;-----------------------------------------------------------------------------
|
||||||
;; 2. Variables
|
;;; 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!
|
;;; You can create a global (dynamically scoped) variable using DEFVAR and
|
||||||
|
;;; DEFPARAMETER. The variable name can use any character except: ()",'`;#|\
|
||||||
|
|
||||||
|
;;; The difference between DEFVAR and DEFPARAMETER is that re-evaluating a
|
||||||
|
;;; DEFVAR expression doesn't change the value of the variable. DEFPARAMETER,
|
||||||
|
;;; on the other hand, does.
|
||||||
|
|
||||||
|
;;; By convention, dynamically scoped variables have earmuffs in their name.
|
||||||
|
|
||||||
(defparameter *some-var* 5)
|
(defparameter *some-var* 5)
|
||||||
*some-var* ; => 5
|
*some-var* ; => 5
|
||||||
|
|
||||||
;; You can also use unicode characters.
|
;;; You can also use unicode characters.
|
||||||
(defparameter *AΛB* nil)
|
(defparameter *AΛB* nil)
|
||||||
|
|
||||||
|
;;; Accessing a previously unbound variable is an undefined behavior, but
|
||||||
|
;;; possible. Don't do it.
|
||||||
|
|
||||||
;; Accessing a previously unbound variable is an
|
;;; You can create local bindings with LET. In the following snippet, `me` is
|
||||||
;; undefined behavior (but possible). Don't do it.
|
;;; 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"
|
||||||
|
|
||||||
|
|
||||||
;; Local binding: `me` is bound to "dance with you" only within the
|
;;;-----------------------------------------------------------------------------;
|
||||||
;; (let ...). Let always returns the value of the last `form` in the
|
;;; 3. Structs and collections
|
||||||
;; let form.
|
;;;-----------------------------------------------------------------------------;
|
||||||
|
|
||||||
(let ((me "dance with you"))
|
|
||||||
me)
|
|
||||||
;; => "dance with you"
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;; Structs
|
||||||
;; 3. Structs and Collections
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
;; Structs
|
|
||||||
(defstruct dog name breed age)
|
(defstruct dog name breed age)
|
||||||
(defparameter *rover*
|
(defparameter *rover*
|
||||||
(make-dog :name "rover"
|
(make-dog :name "rover"
|
||||||
:breed "collie"
|
:breed "collie"
|
||||||
:age 5))
|
:age 5))
|
||||||
*rover* ; => #S(DOG :NAME "rover" :BREED "collie" :AGE 5)
|
*rover* ; => #S(DOG :NAME "rover" :BREED "collie" :AGE 5)
|
||||||
|
(dog-p *rover*) ; => T
|
||||||
(dog-p *rover*) ; => true #| -p signifies "predicate". It's used to
|
|
||||||
check if *rover* is an instance of dog. |#
|
|
||||||
(dog-name *rover*) ; => "rover"
|
(dog-name *rover*) ; => "rover"
|
||||||
|
|
||||||
;; Dog-p, make-dog, and dog-name are all created by defstruct!
|
;;; DOG-P, MAKE-DOG, and DOG-NAME are all automatically created by DEFSTRUCT
|
||||||
|
|
||||||
|
|
||||||
;;; Pairs
|
;;; Pairs
|
||||||
;; `cons' constructs pairs, `car' and `cdr' extract the first
|
|
||||||
;; and second elements
|
;;; CONS constructs pairs. CAR and CDR return the head and tail of a CONS-pair.
|
||||||
|
|
||||||
(cons 'SUBJECT 'VERB) ; => '(SUBJECT . VERB)
|
(cons 'SUBJECT 'VERB) ; => '(SUBJECT . VERB)
|
||||||
(car (cons 'SUBJECT 'VERB)) ; => SUBJECT
|
(car (cons 'SUBJECT 'VERB)) ; => SUBJECT
|
||||||
(cdr (cons 'SUBJECT 'VERB)) ; => VERB
|
(cdr (cons 'SUBJECT 'VERB)) ; => VERB
|
||||||
|
|
||||||
|
|
||||||
;;; Lists
|
;;; Lists
|
||||||
|
|
||||||
;; Lists are linked-list data structures, made of `cons' pairs and end
|
;;; Lists are linked-list data structures, made of CONS pairs and end with a
|
||||||
;; with a `nil' (or '()) to mark the end of the list
|
;;; NIL (or '()) to mark the end of the list
|
||||||
(cons 1 (cons 2 (cons 3 nil))) ; => '(1 2 3)
|
|
||||||
;; `list' is a convenience variadic constructor for lists
|
(cons 1 (cons 2 (cons 3 nil))) ; => '(1 2 3)
|
||||||
(list 1 2 3) ; => '(1 2 3)
|
|
||||||
;; and a quote can also be used for a literal list value
|
;;; LIST is a convenience variadic constructor for lists
|
||||||
'(1 2 3) ; => '(1 2 3)
|
|
||||||
|
(list 1 2 3) ; => '(1 2 3)
|
||||||
|
|
||||||
|
;;; When the first argument to CONS is an atom and the second argument is a
|
||||||
|
;;; list, CONS returns a new CONS-pair with the first argument as the first
|
||||||
|
;;; item and the second argument as the rest of the CONS-pair
|
||||||
|
|
||||||
;; Can still use `cons' to add an item to the beginning of a list
|
|
||||||
(cons 4 '(1 2 3)) ; => '(4 1 2 3)
|
(cons 4 '(1 2 3)) ; => '(4 1 2 3)
|
||||||
|
|
||||||
;; Use `append' to - surprisingly - append lists together
|
;;; Use APPEND to join lists
|
||||||
|
|
||||||
(append '(1 2) '(3 4)) ; => '(1 2 3 4)
|
(append '(1 2) '(3 4)) ; => '(1 2 3 4)
|
||||||
|
|
||||||
;; Or use concatenate -
|
;;; Or CONCATENATE
|
||||||
|
|
||||||
(concatenate 'list '(1 2) '(3 4))
|
(concatenate 'list '(1 2) '(3 4)) ; => '(1 2 3 4)
|
||||||
|
|
||||||
|
;;; Lists are a very central type, so there is a wide variety of functionality for
|
||||||
|
;;; them, a few examples:
|
||||||
|
|
||||||
;; Lists are a very central type, so there is a wide variety of functionality for
|
|
||||||
;; them, a few examples:
|
|
||||||
(mapcar #'1+ '(1 2 3)) ; => '(2 3 4)
|
(mapcar #'1+ '(1 2 3)) ; => '(2 3 4)
|
||||||
(mapcar #'+ '(1 2 3) '(10 20 30)) ; => '(11 22 33)
|
(mapcar #'+ '(1 2 3) '(10 20 30)) ; => '(11 22 33)
|
||||||
(remove-if-not #'evenp '(1 2 3 4)) ; => '(2 4)
|
(remove-if-not #'evenp '(1 2 3 4)) ; => '(2 4)
|
||||||
(every #'evenp '(1 2 3 4)) ; => nil
|
(every #'evenp '(1 2 3 4)) ; => NIL
|
||||||
(some #'oddp '(1 2 3 4)) ; => T
|
(some #'oddp '(1 2 3 4)) ; => T
|
||||||
(butlast '(subject verb object)) ; => (SUBJECT VERB)
|
(butlast '(subject verb object)) ; => (SUBJECT VERB)
|
||||||
|
|
||||||
|
|
||||||
;;; Vectors
|
;;; Vectors
|
||||||
|
|
||||||
;; Vector's literals are fixed-length arrays
|
;;; Vector's literals are fixed-length arrays
|
||||||
|
|
||||||
#(1 2 3) ; => #(1 2 3)
|
#(1 2 3) ; => #(1 2 3)
|
||||||
|
|
||||||
;; Use concatenate to add vectors together
|
;;; Use CONCATENATE to add vectors together
|
||||||
|
|
||||||
(concatenate 'vector #(1 2 3) #(4 5 6)) ; => #(1 2 3 4 5 6)
|
(concatenate 'vector #(1 2 3) #(4 5 6)) ; => #(1 2 3 4 5 6)
|
||||||
|
|
||||||
|
|
||||||
;;; Arrays
|
;;; Arrays
|
||||||
|
|
||||||
;; Both vectors and strings are special-cases of arrays.
|
;;; Both vectors and strings are special-cases of arrays.
|
||||||
|
|
||||||
;; 2D arrays
|
;;; 2D arrays
|
||||||
|
|
||||||
(make-array (list 2 2))
|
(make-array (list 2 2)) ; => #2A((0 0) (0 0))
|
||||||
|
(make-array '(2 2)) ; => #2A((0 0) (0 0))
|
||||||
|
(make-array (list 2 2 2)) ; => #3A(((0 0) (0 0)) ((0 0) (0 0)))
|
||||||
|
|
||||||
;; (make-array '(2 2)) works as well.
|
;;; Caution: the default initial values of MAKE-ARRAY are implementation-defined.
|
||||||
|
;;; To explicitly specify them:
|
||||||
|
|
||||||
; => #2A((0 0) (0 0))
|
(make-array '(2) :initial-element 'unset) ; => #(UNSET UNSET)
|
||||||
|
|
||||||
(make-array (list 2 2 2))
|
;;; To access the element at 1, 1, 1:
|
||||||
|
|
||||||
; => #3A(((0 0) (0 0)) ((0 0) (0 0)))
|
(aref (make-array (list 2 2 2)) 1 1 1) ; => 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 (list 2 2 2)) 1 1 1)
|
|
||||||
|
|
||||||
; => 0
|
|
||||||
|
|
||||||
;;; Adjustable vectors
|
;;; Adjustable vectors
|
||||||
|
|
||||||
;; Adjustable vectors have the same printed representation
|
;;; Adjustable vectors have the same printed representation as
|
||||||
;; as fixed-length vector's literals.
|
;;; fixed-length vector's literals.
|
||||||
|
|
||||||
(defparameter *adjvec* (make-array '(3) :initial-contents '(1 2 3)
|
(defparameter *adjvec* (make-array '(3) :initial-contents '(1 2 3)
|
||||||
:adjustable t :fill-pointer t))
|
:adjustable t :fill-pointer t))
|
||||||
|
|
||||||
*adjvec* ; => #(1 2 3)
|
*adjvec* ; => #(1 2 3)
|
||||||
|
|
||||||
;; Adding new element:
|
;;; Adding new elements
|
||||||
(vector-push-extend 4 *adjvec*) ; => 3
|
|
||||||
|
|
||||||
|
(vector-push-extend 4 *adjvec*) ; => 3
|
||||||
*adjvec* ; => #(1 2 3 4)
|
*adjvec* ; => #(1 2 3 4)
|
||||||
|
|
||||||
|
|
||||||
|
;;; Sets, naively, are just lists:
|
||||||
;;; Naively, sets are just lists:
|
|
||||||
|
|
||||||
(set-difference '(1 2 3 4) '(4 5 6 7)) ; => (3 2 1)
|
(set-difference '(1 2 3 4) '(4 5 6 7)) ; => (3 2 1)
|
||||||
(intersection '(1 2 3 4) '(4 5 6 7)) ; => 4
|
(intersection '(1 2 3 4) '(4 5 6 7)) ; => 4
|
||||||
(union '(1 2 3 4) '(4 5 6 7)) ; => (3 2 1 4 5 6 7)
|
(union '(1 2 3 4) '(4 5 6 7)) ; => (3 2 1 4 5 6 7)
|
||||||
(adjoin 4 '(1 2 3 4)) ; => (1 2 3 4)
|
(adjoin 4 '(1 2 3 4)) ; => (1 2 3 4)
|
||||||
|
|
||||||
;; But you'll want to use a better data structure than a linked list
|
;;; However, you'll need a better data structure than linked lists when working
|
||||||
;; for performant work!
|
;;; with larger data sets
|
||||||
|
|
||||||
;;; Dictionaries are implemented as hash tables.
|
;;; Dictionaries are implemented as hash tables.
|
||||||
|
|
||||||
;; Create a hash table
|
;;; Create a hash table
|
||||||
|
|
||||||
(defparameter *m* (make-hash-table))
|
(defparameter *m* (make-hash-table))
|
||||||
|
|
||||||
;; set a value
|
;;; Set value
|
||||||
|
|
||||||
(setf (gethash 'a *m*) 1)
|
(setf (gethash 'a *m*) 1)
|
||||||
|
|
||||||
;; Retrieve a value
|
;;; Retrieve value
|
||||||
(gethash 'a *m*) ; => 1, t
|
|
||||||
|
|
||||||
;; Detail - Common Lisp has multiple return values possible. gethash
|
(gethash 'a *m*) ; => 1, T
|
||||||
;; returns t in the second value if anything was found, and nil if
|
|
||||||
;; not.
|
|
||||||
|
|
||||||
;; Retrieving a non-present value returns nil
|
;;; CL expressions have the ability to return multiple values.
|
||||||
(gethash 'd *m*) ;=> nil, nil
|
|
||||||
|
(values 1 2) ; => 1, 2
|
||||||
|
|
||||||
|
;;; which can be bound with MULTIPLE-VALUE-BIND
|
||||||
|
|
||||||
|
(multiple-value-bind (x y)
|
||||||
|
(values 1 2)
|
||||||
|
(list y x))
|
||||||
|
|
||||||
|
; => '(2 1)
|
||||||
|
|
||||||
|
;;; GETHASH is an example of a function that returns multiple values. The first
|
||||||
|
;;; value it return is the value of the key in the hash table; if the key is
|
||||||
|
;;; not found it returns NIL.
|
||||||
|
|
||||||
|
;;; The second value determines if that key is indeed present in the hash
|
||||||
|
;;; table. If a key is not found in the table it returns NIL. This behavior
|
||||||
|
;;; allows us to check if the value of a key is actually NIL.
|
||||||
|
|
||||||
|
;;; Retrieving a non-present value returns nil
|
||||||
|
|
||||||
|
(gethash 'd *m*) ;=> NIL, NIL
|
||||||
|
|
||||||
|
;;; You can provide a default value for missing keys
|
||||||
|
|
||||||
;; You can provide a default value for missing keys
|
|
||||||
(gethash 'd *m* :not-found) ; => :NOT-FOUND
|
(gethash 'd *m* :not-found) ; => :NOT-FOUND
|
||||||
|
|
||||||
;; Let's handle the multiple return values here in code.
|
;;; Let's handle the multiple return values here in code.
|
||||||
|
|
||||||
(multiple-value-bind
|
(multiple-value-bind (a b)
|
||||||
(a b)
|
|
||||||
(gethash 'd *m*)
|
(gethash 'd *m*)
|
||||||
(list a b))
|
(list a b))
|
||||||
; => (NIL NIL)
|
; => (NIL NIL)
|
||||||
|
|
||||||
(multiple-value-bind
|
(multiple-value-bind (a b)
|
||||||
(a b)
|
|
||||||
(gethash 'a *m*)
|
(gethash 'a *m*)
|
||||||
(list a b))
|
(list a b))
|
||||||
; => (1 T)
|
; => (1 T)
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; 3. Functions
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
;; Use `lambda' to create anonymous functions.
|
;;;-----------------------------------------------------------------------------
|
||||||
;; A function always returns the value of its last expression.
|
;;; 3. Functions
|
||||||
;; The exact printable representation of a function will vary...
|
;;;-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
;;; Use LAMBDA to create anonymous functions. Functions always returns the
|
||||||
|
;;; value of the last expression. The exact printable representation of a
|
||||||
|
;;; function varies between implementations.
|
||||||
|
|
||||||
(lambda () "Hello World") ; => #<FUNCTION (LAMBDA ()) {1004E7818B}>
|
(lambda () "Hello World") ; => #<FUNCTION (LAMBDA ()) {1004E7818B}>
|
||||||
|
|
||||||
;; Use funcall to call lambda functions
|
;;; Use FUNCALL to call anonymous functions
|
||||||
(funcall (lambda () "Hello World")) ; => "Hello World"
|
|
||||||
|
|
||||||
;; Or Apply
|
(funcall (lambda () "Hello World")) ; => "Hello World"
|
||||||
|
(funcall #'+ 1 2 3) ; => 6
|
||||||
|
|
||||||
|
;;; A call to FUNCALL is also implied when the lambda expression is the CAR of
|
||||||
|
;;; an unquoted list
|
||||||
|
|
||||||
|
((lambda () "Hello World")) ; => "Hello World"
|
||||||
|
((lambda (val) val) "Hello World") ; => "Hello World"
|
||||||
|
|
||||||
|
;;; FUNCALL is used when the arguments are known beforehand. Otherwise, use APPLY
|
||||||
|
|
||||||
|
(apply #'+ '(1 2 3)) ; => 6
|
||||||
(apply (lambda () "Hello World") nil) ; => "Hello World"
|
(apply (lambda () "Hello World") nil) ; => "Hello World"
|
||||||
|
|
||||||
;; De-anonymize the function
|
;;; To name a function, use DEFUN
|
||||||
(defun hello-world ()
|
|
||||||
"Hello World")
|
(defun hello-world () "Hello World")
|
||||||
(hello-world) ; => "Hello World"
|
(hello-world) ; => "Hello World"
|
||||||
|
|
||||||
;; The () in the above is the list of arguments for the function
|
;;; The () in the definition above is the list of arguments
|
||||||
(defun hello (name)
|
|
||||||
(format nil "Hello, ~a" name))
|
|
||||||
|
|
||||||
|
(defun hello (name) (format nil "Hello, ~A" name))
|
||||||
(hello "Steve") ; => "Hello, Steve"
|
(hello "Steve") ; => "Hello, Steve"
|
||||||
|
|
||||||
;; Functions can have optional arguments; they default to nil
|
;;; Functions can have optional arguments; they default to NIL
|
||||||
|
|
||||||
(defun hello (name &optional from)
|
(defun hello (name &optional from)
|
||||||
(if from
|
(if from
|
||||||
(format t "Hello, ~a, from ~a" name from)
|
(format t "Hello, ~A, from ~A" name from)
|
||||||
(format t "Hello, ~a" name)))
|
(format t "Hello, ~A" name)))
|
||||||
|
|
||||||
(hello "Jim" "Alpacas") ;; => Hello, Jim, from Alpacas
|
(hello "Jim" "Alpacas") ; => Hello, Jim, from Alpacas
|
||||||
|
|
||||||
|
;;; The default values can also be specified
|
||||||
|
|
||||||
;; And the defaults can be set...
|
|
||||||
(defun hello (name &optional (from "The world"))
|
(defun hello (name &optional (from "The world"))
|
||||||
(format t "Hello, ~a, from ~a" name from))
|
(format nil "Hello, ~A, from ~A" name from))
|
||||||
|
|
||||||
(hello "Steve")
|
(hello "Steve") ; => Hello, Steve, from The world
|
||||||
; => Hello, Steve, from The world
|
(hello "Steve" "the alpacas") ; => Hello, Steve, from the alpacas
|
||||||
|
|
||||||
(hello "Steve" "the alpacas")
|
;;; Functions also have keyword arguments to allow non-positional arguments
|
||||||
; => Hello, Steve, from the alpacas
|
|
||||||
|
|
||||||
|
|
||||||
;; And of course, keywords are allowed as well... usually more
|
|
||||||
;; flexible than &optional.
|
|
||||||
|
|
||||||
(defun generalized-greeter (name &key (from "the world") (honorific "Mx"))
|
(defun generalized-greeter (name &key (from "the world") (honorific "Mx"))
|
||||||
(format t "Hello, ~a ~a, from ~a" honorific name from))
|
(format t "Hello, ~A ~A, from ~A" honorific name from))
|
||||||
|
|
||||||
(generalized-greeter "Jim") ; => Hello, Mx Jim, from the world
|
(generalized-greeter "Jim")
|
||||||
|
; => Hello, Mx Jim, from the world
|
||||||
|
|
||||||
(generalized-greeter "Jim" :from "the alpacas you met last summer" :honorific "Mr")
|
(generalized-greeter "Jim" :from "the alpacas you met last summer" :honorific "Mr")
|
||||||
; => Hello, Mr Jim, from the alpacas you met last summer
|
; => Hello, Mr Jim, from the alpacas you met last summer
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; 4. Equality
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
;; Common Lisp has a sophisticated equality system. A couple are covered here.
|
;;;-----------------------------------------------------------------------------
|
||||||
|
;;; 4. Equality
|
||||||
|
;;;-----------------------------------------------------------------------------
|
||||||
|
|
||||||
;; for numbers use `='
|
;;; CL has a sophisticated equality system. Some are covered here.
|
||||||
(= 3 3.0) ; => t
|
|
||||||
(= 2 1) ; => nil
|
|
||||||
|
|
||||||
;; for object identity (approximately) use `eql`
|
;;; For numbers, use `='
|
||||||
(eql 3 3) ; => t
|
(= 3 3.0) ; => T
|
||||||
(eql 3 3.0) ; => nil
|
(= 2 1) ; => NIL
|
||||||
(eql (list 3) (list 3)) ; => nil
|
|
||||||
|
|
||||||
;; for lists, strings, and bit-vectors use `equal'
|
;;; For object identity (approximately) use EQL
|
||||||
(equal (list 'a 'b) (list 'a 'b)) ; => t
|
(eql 3 3) ; => T
|
||||||
(equal (list 'a 'b) (list 'b 'a)) ; => nil
|
(eql 3 3.0) ; => NIL
|
||||||
|
(eql (list 3) (list 3)) ; => NIL
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;; for lists, strings, and bit-vectors use EQUAL
|
||||||
;; 5. Control Flow
|
(equal (list 'a 'b) (list 'a 'b)) ; => T
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
(equal (list 'a 'b) (list 'b 'a)) ; => NIL
|
||||||
|
|
||||||
|
|
||||||
|
;;;-----------------------------------------------------------------------------
|
||||||
|
;;; 5. Control Flow
|
||||||
|
;;;-----------------------------------------------------------------------------
|
||||||
|
|
||||||
;;; Conditionals
|
;;; Conditionals
|
||||||
|
|
||||||
@ -404,71 +462,75 @@ nil ; for false - and the empty list
|
|||||||
"this is false") ; else expression
|
"this is false") ; else expression
|
||||||
; => "this is true"
|
; => "this is true"
|
||||||
|
|
||||||
;; In conditionals, all non-nil values are treated as true
|
;;; In conditionals, all non-NIL values are treated as true
|
||||||
|
|
||||||
(member 'Groucho '(Harpo Groucho Zeppo)) ; => '(GROUCHO ZEPPO)
|
(member 'Groucho '(Harpo Groucho Zeppo)) ; => '(GROUCHO ZEPPO)
|
||||||
(if (member 'Groucho '(Harpo Groucho Zeppo))
|
(if (member 'Groucho '(Harpo Groucho Zeppo))
|
||||||
'yep
|
'yep
|
||||||
'nope)
|
'nope)
|
||||||
; => 'YEP
|
; => 'YEP
|
||||||
|
|
||||||
;; `cond' chains a series of tests to select a result
|
;;; COND chains a series of tests to select a result
|
||||||
(cond ((> 2 2) (error "wrong!"))
|
(cond ((> 2 2) (error "wrong!"))
|
||||||
((< 2 2) (error "wrong again!"))
|
((< 2 2) (error "wrong again!"))
|
||||||
(t 'ok)) ; => 'OK
|
(t 'ok)) ; => 'OK
|
||||||
|
|
||||||
;; Typecase switches on the type of the value
|
;;; TYPECASE switches on the type of the value
|
||||||
(typecase 1
|
(typecase 1
|
||||||
(string :string)
|
(string :string)
|
||||||
(integer :int))
|
(integer :int))
|
||||||
|
|
||||||
; => :int
|
; => :int
|
||||||
|
|
||||||
|
|
||||||
|
;;; Looping
|
||||||
|
|
||||||
|
;;; Recursion
|
||||||
|
|
||||||
|
(defun fact (n)
|
||||||
|
(if (< n 2)
|
||||||
|
1
|
||||||
|
(* n (fact(- n 1)))))
|
||||||
|
|
||||||
|
(fact 5) ; => 120
|
||||||
|
|
||||||
;;; Iteration
|
;;; Iteration
|
||||||
|
|
||||||
;; Of course recursion is supported:
|
(defun fact (n)
|
||||||
|
(loop :for result = 1 :then (* result i)
|
||||||
|
:for i :from 2 :to n
|
||||||
|
:finally (return result)))
|
||||||
|
|
||||||
(defun walker (n)
|
(fact 5) ; => 120
|
||||||
(if (zerop n)
|
|
||||||
:walked
|
|
||||||
(walker (- n 1))))
|
|
||||||
|
|
||||||
(walker 5) ; => :walked
|
|
||||||
|
|
||||||
;; Most of the time, we use DOLIST or LOOP
|
|
||||||
|
|
||||||
|
(loop :for x :across "abc" :collect x)
|
||||||
|
; => (#\a #\b #\c #\d)
|
||||||
|
|
||||||
(dolist (i '(1 2 3 4))
|
(dolist (i '(1 2 3 4))
|
||||||
(format t "~a" i))
|
(format t "~A" i))
|
||||||
|
|
||||||
; => 1234
|
; => 1234
|
||||||
|
|
||||||
(loop for i from 0 below 10
|
|
||||||
collect i)
|
|
||||||
|
|
||||||
; => (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.
|
||||||
;; 6. Mutation
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
;; Use `setf' to assign a new value to an existing variable. This was
|
|
||||||
;; demonstrated earlier in the hash table example.
|
|
||||||
|
|
||||||
(let ((variable 10))
|
(let ((variable 10))
|
||||||
(setf variable 2))
|
(setf variable 2))
|
||||||
; => 2
|
; => 2
|
||||||
|
|
||||||
|
;;; Good Lisp style is to minimize the use of destructive functions and to avoid
|
||||||
|
;;; mutation when reasonable.
|
||||||
|
|
||||||
;; Good Lisp style is to minimize destructive functions and to avoid
|
|
||||||
;; mutation when reasonable.
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;-----------------------------------------------------------------------------
|
||||||
;; 7. Classes and Objects
|
;;; 7. Classes and objects
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;-----------------------------------------------------------------------------
|
||||||
|
|
||||||
;; No more Animal classes, let's have Human-Powered Mechanical
|
;;; No more animal classes. Let's have Human-Powered Mechanical
|
||||||
;; Conveyances.
|
;;; Conveyances.
|
||||||
|
|
||||||
(defclass human-powered-conveyance ()
|
(defclass human-powered-conveyance ()
|
||||||
((velocity
|
((velocity
|
||||||
@ -479,14 +541,16 @@ nil ; for false - and the empty list
|
|||||||
:initarg :average-efficiency))
|
:initarg :average-efficiency))
|
||||||
(:documentation "A human powered conveyance"))
|
(:documentation "A human powered conveyance"))
|
||||||
|
|
||||||
;; defclass, followed by name, followed by the superclass list,
|
;;; The arguments to DEFCLASS, in order are:
|
||||||
;; followed by slot list, followed by optional qualities such as
|
;;; 1. class name
|
||||||
;; :documentation.
|
;;; 2. superclass list
|
||||||
|
;;; 3. slot list
|
||||||
|
;;; 4. optional specifiers
|
||||||
|
|
||||||
;; When no superclass list is set, the empty list defaults to the
|
;;; When no superclass list is set, the empty list defaults to the
|
||||||
;; standard-object class. This *can* be changed, but not until you
|
;;; standard-object class. This *can* be changed, but not until you
|
||||||
;; know what you're doing. Look up the Art of the Metaobject Protocol
|
;;; know what you're doing. Look up the Art of the Metaobject Protocol
|
||||||
;; for more information.
|
;;; for more information.
|
||||||
|
|
||||||
(defclass bicycle (human-powered-conveyance)
|
(defclass bicycle (human-powered-conveyance)
|
||||||
((wheel-size
|
((wheel-size
|
||||||
@ -509,8 +573,7 @@ nil ; for false - and the empty list
|
|||||||
:accessor number-of-rowers
|
:accessor number-of-rowers
|
||||||
:initarg :number-of-rowers)))
|
:initarg :number-of-rowers)))
|
||||||
|
|
||||||
|
;;; Calling DESCRIBE on the HUMAN-POWERED-CONVEYANCE class in the REPL gives:
|
||||||
;; Calling DESCRIBE on the human-powered-conveyance class in the REPL gives:
|
|
||||||
|
|
||||||
(describe 'human-powered-conveyance)
|
(describe 'human-powered-conveyance)
|
||||||
|
|
||||||
@ -532,47 +595,42 @@ nil ; for false - and the empty list
|
|||||||
; Readers: AVERAGE-EFFICIENCY
|
; Readers: AVERAGE-EFFICIENCY
|
||||||
; Writers: (SETF AVERAGE-EFFICIENCY)
|
; Writers: (SETF AVERAGE-EFFICIENCY)
|
||||||
|
|
||||||
;; Note the reflective behavior available to you! Common Lisp is
|
;;; Note the reflective behavior available. CL was designed to be an
|
||||||
;; designed to be an interactive system
|
;;; interactive system
|
||||||
|
|
||||||
;; To define a method, let's find out what our circumference of the
|
;;; 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
|
;;; bike wheel turns out to be using the equation: C = d * pi
|
||||||
|
|
||||||
(defmethod circumference ((object bicycle))
|
(defmethod circumference ((object bicycle))
|
||||||
(* pi (wheel-size object)))
|
(* pi (wheel-size object)))
|
||||||
|
|
||||||
;; pi is defined in Lisp already for us!
|
;;; PI is defined as a built-in in CL
|
||||||
|
|
||||||
;; Let's suppose we find out that the efficiency value of the number
|
;;; 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
|
;;; of rowers in a canoe is roughly logarithmic. This should probably be set
|
||||||
;; in the constructor/initializer.
|
;;; in the constructor/initializer.
|
||||||
|
|
||||||
;; Here's how to initialize your instance after Common Lisp gets done
|
;;; To initialize your instance after CL gets done constructing it:
|
||||||
;; constructing it:
|
|
||||||
|
|
||||||
(defmethod initialize-instance :after ((object canoe) &rest args)
|
(defmethod initialize-instance :after ((object canoe) &rest args)
|
||||||
(setf (average-efficiency object) (log (1+ (number-of-rowers object)))))
|
(setf (average-efficiency object) (log (1+ (number-of-rowers object)))))
|
||||||
|
|
||||||
;; Then to construct an instance and check the average efficiency...
|
;;; Then to construct an instance and check the average efficiency...
|
||||||
|
|
||||||
(average-efficiency (make-instance 'canoe :number-of-rowers 15))
|
(average-efficiency (make-instance 'canoe :number-of-rowers 15))
|
||||||
; => 2.7725887
|
; => 2.7725887
|
||||||
|
|
||||||
|
|
||||||
|
;;;-----------------------------------------------------------------------------
|
||||||
|
;;; 8. Macros
|
||||||
|
;;;-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
;;; Macros let you extend the syntax of the language. CL doesn't come
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;; with a WHILE loop, however, it's trivial to write one. If we obey our
|
||||||
;; 8. Macros
|
;;; assembler instincts, we wind up with:
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
;; 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:
|
|
||||||
|
|
||||||
(defmacro while (condition &body body)
|
(defmacro while (condition &body body)
|
||||||
"While `condition` is true, `body` is executed.
|
"While `condition` is true, `body` is executed.
|
||||||
|
|
||||||
`condition` is tested prior to each execution of `body`"
|
`condition` is tested prior to each execution of `body`"
|
||||||
(let ((block-name (gensym)) (done (gensym)))
|
(let ((block-name (gensym)) (done (gensym)))
|
||||||
`(tagbody
|
`(tagbody
|
||||||
@ -584,47 +642,47 @@ nil ; for false - and the empty list
|
|||||||
(go ,block-name)
|
(go ,block-name)
|
||||||
,done)))
|
,done)))
|
||||||
|
|
||||||
;; Let's look at the high-level version of this:
|
;;; Let's look at the high-level version of this:
|
||||||
|
|
||||||
|
|
||||||
(defmacro while (condition &body body)
|
(defmacro while (condition &body body)
|
||||||
"While `condition` is true, `body` is executed.
|
"While `condition` is true, `body` is executed.
|
||||||
|
|
||||||
`condition` is tested prior to each execution of `body`"
|
`condition` is tested prior to each execution of `body`"
|
||||||
`(loop while ,condition
|
`(loop while ,condition
|
||||||
do
|
do
|
||||||
(progn
|
(progn
|
||||||
,@body)))
|
,@body)))
|
||||||
|
|
||||||
;; However, with a modern compiler, this is not required; the LOOP
|
;;; However, with a modern compiler, this is not required; the LOOP form
|
||||||
;; form compiles equally well and is easier to read.
|
;;; compiles equally well and is easier to read.
|
||||||
|
|
||||||
;; Note that ``` is used, as well as `,` and `@`. ``` is a quote-type operator
|
;;; Note that ``` is used, as well as `,` and `@`. ``` is a quote-type operator
|
||||||
;; known as quasiquote; it allows the use of `,` . `,` allows "unquoting"
|
;;; known as quasiquote; it allows the use of `,` . `,` allows "unquoting"
|
||||||
;; variables. @ interpolates lists.
|
;;; variables. @ interpolates lists.
|
||||||
|
|
||||||
;; Gensym creates a unique symbol guaranteed to not exist elsewhere in
|
;;; GENSYM creates a unique symbol guaranteed to not exist elsewhere in
|
||||||
;; the system. This is because macros are expanded at compile time and
|
;;; the system. This is because macros are expanded at compile time and
|
||||||
;; variables declared in the macro can collide with variables used in
|
;;; variables declared in the macro can collide with variables used in
|
||||||
;; regular code.
|
;;; regular code.
|
||||||
|
|
||||||
;; See Practical Common Lisp for more information on macros.
|
;;; See Practical Common Lisp and On Lisp for more information on macros.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Further Reading
|
## Further reading
|
||||||
|
|
||||||
* [Keep moving on to the Practical Common Lisp book.](http://www.gigamonkeys.com/book/)
|
- [Practical Common Lisp](http://www.gigamonkeys.com/book/)
|
||||||
* [A Gentle Introduction to...](https://www.cs.cmu.edu/~dst/LispBook/book.pdf)
|
- [Common Lisp: A Gentle Introduction to Symbolic Computation](https://www.cs.cmu.edu/~dst/LispBook/book.pdf)
|
||||||
|
|
||||||
|
|
||||||
## Extra Info
|
## Extra information
|
||||||
|
|
||||||
* [CLiki](http://www.cliki.net/)
|
- [CLiki](http://www.cliki.net/)
|
||||||
* [common-lisp.net](https://common-lisp.net/)
|
- [common-lisp.net](https://common-lisp.net/)
|
||||||
* [Awesome Common Lisp](https://github.com/CodyReichert/awesome-cl)
|
- [Awesome Common Lisp](https://github.com/CodyReichert/awesome-cl)
|
||||||
|
- [Lisp Lang](http://lisp-lang.org/)
|
||||||
|
|
||||||
## Credits.
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
Lots of thanks to the Scheme people for rolling up a great starting
|
Lots of thanks to the Scheme people for rolling up a great starting
|
||||||
point which could be easily moved to Common Lisp.
|
point which could be easily moved to Common Lisp.
|
||||||
|
Loading…
Reference in New Issue
Block a user