summaryrefslogtreecommitdiffhomepage
path: root/common-lisp.html.markdown
diff options
context:
space:
mode:
authorRommel Martinez <ebzzry@ebzzry.io>2018-03-01 21:25:04 +0800
committerRommel Martinez <ebzzry@ebzzry.io>2018-03-01 21:25:04 +0800
commit6968c5724892ec0ea787929a307552d3dd211974 (patch)
tree65ba666aaea987215952d88a56517deb7e770701 /common-lisp.html.markdown
parent9f33f260dc305a40b6476c081ea16e75ac2ced50 (diff)
[common-lisp/en]: clean up and add more information
Diffstat (limited to 'common-lisp.html.markdown')
-rw-r--r--common-lisp.html.markdown662
1 files changed, 360 insertions, 302 deletions
diff --git a/common-lisp.html.markdown b/common-lisp.html.markdown
index 9a23bc26..5f6975b6 100644
--- a/common-lisp.html.markdown
+++ b/common-lisp.html.markdown
@@ -4,82 +4,91 @@ language: "Common Lisp"
filename: commonlisp.lisp
contributors:
- ["Paul Nathan", "https://github.com/pnathan"]
+ - ["Rommel Martinez", "https://ebzzry.io"]
---
-ANSI Common Lisp is a general purpose, multi-paradigm programming
-language suited for a wide variety of industry applications. It is
-frequently referred to as a programmable programming language.
+Common Lisp is a general-purpose, multi-paradigm programming language suited for a wide variety of
+industry applications. It is frequently referred to as a programmable programming language.
-The classic starting point is [Practical Common Lisp and freely available.](http://www.gigamonkeys.com/book/)
-
-Another popular and recent book is
-[Land of Lisp](http://landoflisp.com/).
+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,
+[Common Lisp Recipes](http://weitz.de/cl-recipes/), was recently published.
```common_lisp
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;-----------------------------------------------------------------------------
;;; 0. Syntax
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;-----------------------------------------------------------------------------
-;;; General form.
+;;; General form
-;; Lisp has two fundamental pieces of syntax: the ATOM and the
-;; S-expression. Typically, grouped S-expressions are called `forms`.
+;;; CL has two fundamental pieces of syntax: ATOM and S-EXPRESSION.
+;;; 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
+t ; another atom, denoting true
+(+ 1 2 3 4) ; an s-expression
+'(4 :foo t) ; another s-expression
-:THING ;Another atom; evaluating to the symbol :thing.
-t ; another atom, denoting true.
+;;; Comments
-(+ 1 2 3 4) ; an s-expression
+;;; Single-line comments start with a semicolon; use four for file-level
+;;; comments, three for section descriptions, two inside definitions, and one
+;;; for single lines. For example,
-'(4 :foo t) ;another one
+;;;; life.lisp
+;;; Foo bar baz, because quu quux. Optimized for maximum krakaboom and umph.
+;;; Needed by the function LINULUKO.
-;;; Comments
+(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
-;; Single line comments start with a semicolon; use two for normal
-;; comments, three for section comments, and four for file-level
-;; comments.
+;;; Block comments, on the other hand, allow for free-form comments. They are
+;;; delimited with #| and |#
-#| Block comments
- can span multiple lines and...
+#| This is a block comment which
+ 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.
+;;; Environment
-;; 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
-;; (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.
+;;; CL is usually developed with a text editor and a Real Eval Print
+;;; Loop (REPL) running at the same time. The REPL allows for interactive
+;;; exploration of the program while it is running "live".
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; 1. Primitive Datatypes and Operators
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;-----------------------------------------------------------------------------
+;;; 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 manually creates a symbol from a string.
-(intern "AAAA") ; => AAAA
-
-(intern "aaa") ; => |aaa|
+(intern "AAAA") ; => AAAA
+(intern "aaa") ; => |aaa|
;;; Numbers
+
9999999999999999999999 ; integers
#b111 ; binary => 7
#o111 ; octal => 73
@@ -89,313 +98,362 @@ t ; another atom, denoting true.
1/2 ; ratios
#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 '
+
+'(+ 1 2) ; => (+ 1 2)
+'a ; => A
+
+;;; Basic arithmetic operations
+
+(+ 1 1) ; => 2
+(- 8 1) ; => 7
+(* 10 2) ; => 20
+(expt 2 3) ; => 8
+(mod 5 2) ; => 1
+(/ 35 5) ; => 7
+(/ 1 3) ; => 1/3
+(+ #C(1 2) #C(6 -4)) ; => #C(7 -2)
+
+;;; Booleans
+
+t ; true; any non-NIL value is true
+nil ; false; also, the empty list: ()
+(not nil) ; => T
+(and 0 t) ; => T
+(or 0 nil) ; => 0
+
+;;; Characters
+
+#\A ; => #\A
+#\λ ; => #\GREEK_SMALL_LETTER_LAMDA
+#\u03BB ; => #\GREEK_SMALL_LETTER_LAMDA
+
+;;; Strings are fixed-length arrays of characters
-;; 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)
-;; You can also call a function manually:
-(funcall #'+ 1 2 3) ; => 6
-;; Some arithmetic operations
-(+ 1 1) ; => 2
-(- 8 1) ; => 7
-(* 10 2) ; => 20
-(expt 2 3) ; => 8
-(mod 5 2) ; => 1
-(/ 35 5) ; => 7
-(/ 1 3) ; => 1/3
-(+ #C(1 2) #C(6 -4)) ; => #C(7 -2)
-
- ;;; Booleans
-t ; for true (any not-nil value is true)
-nil ; for false - and the empty list
-(not nil) ; => t
-(and 0 t) ; => t
-(or 0 nil) ; => 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!"
+;;; Strings can be concatenated
+
+(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
-;; format can be used to format strings:
-(format nil "~a can be ~a" "strings" "formatted")
+;;; FORMAT is used to create formatted output, which ranges from simple string
+;;; 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.
+
+(format nil "~A, ~A!" "Hello" "world") ; => "Hello, world!"
+(format t "~A, ~A!" "Hello" "world") ; => NIL
-;; Printing is pretty easy; ~% is the format specifier for newline.
-(format t "Common Lisp is groovy. Dude.~%")
+;;;-----------------------------------------------------------------------------
+;;; 2. Variables
+;;;-----------------------------------------------------------------------------
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; 2. Variables
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; You can create a global (dynamically scoped) using defparameter
-;; a variable name can use any character except: ()",'`;#|\
+;;; You can create a global (dynamically scoped) variable using DEFVAR and
+;;; DEFPARAMETER. The variable name can use any character except: ()",'`;#|\
-;; Dynamically scoped variables should have earmuffs in their name!
+;;; 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)
*some-var* ; => 5
-;; You can also use unicode characters.
+;;; 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.
+
+;;; You can create local bindings with LET. In the following snippet, `me` is
+;;; bound to "dance with you" only within the (let ...). LET always returns
+;;; the value of the last `form` in the LET form.
-;; Accessing a previously unbound variable is an
-;; undefined behavior (but possible). Don't do it.
+(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
-;; let form.
+;;;-----------------------------------------------------------------------------;
+;;; 3. Structs and collections
+;;;-----------------------------------------------------------------------------;
-(let ((me "dance with you"))
- me)
-;; => "dance with you"
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; 3. Structs and Collections
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Structs
-;; Structs
(defstruct dog name breed age)
(defparameter *rover*
(make-dog :name "rover"
:breed "collie"
:age 5))
-*rover* ; => #S(DOG :NAME "rover" :BREED "collie" :AGE 5)
-
-(dog-p *rover*) ; => true #| -p signifies "predicate". It's used to
- check if *rover* is an instance of dog. |#
+*rover* ; => #S(DOG :NAME "rover" :BREED "collie" :AGE 5)
+(dog-p *rover*) ; => T
(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
-;; `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
+
+;;; CONS constructs pairs. CAR and CDR return the head and tail of a CONS-pair.
+
+(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
-(cons 1 (cons 2 (cons 3 nil))) ; => '(1 2 3)
-;; `list' is a convenience variadic constructor for lists
-(list 1 2 3) ; => '(1 2 3)
-;; and a quote can also be used for a literal list value
-'(1 2 3) ; => '(1 2 3)
+;;; Lists are linked-list data structures, made of CONS pairs and end with a
+;;; 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
+
+(list 1 2 3) ; => '(1 2 3)
-;; Can still use `cons' to add an item to the beginning of a list
-(cons 4 '(1 2 3)) ; => '(4 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
-;; Use `append' to - surprisingly - append lists together
-(append '(1 2) '(3 4)) ; => '(1 2 3 4)
+(cons 4 '(1 2 3)) ; => '(4 1 2 3)
-;; Or use concatenate -
+;;; Use APPEND to join lists
-(concatenate 'list '(1 2) '(3 4))
+(append '(1 2) '(3 4)) ; => '(1 2 3 4)
+
+;;; Or CONCATENATE
+
+(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 2 3) '(10 20 30)) ; => '(11 22 33)
(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
(butlast '(subject verb object)) ; => (SUBJECT VERB)
;;; Vectors
-;; Vector's literals are fixed-length arrays
-#(1 2 3) ; => #(1 2 3)
-
-;; Use concatenate to add vectors together
-(concatenate 'vector #(1 2 3) #(4 5 6)) ; => #(1 2 3 4 5 6)
+;;; Vector's literals are fixed-length arrays
-;;; Arrays
+#(1 2 3) ; => #(1 2 3)
-;; Both vectors and strings are special-cases of arrays.
+;;; Use CONCATENATE to add vectors together
-;; 2D arrays
+(concatenate 'vector #(1 2 3) #(4 5 6)) ; => #(1 2 3 4 5 6)
-(make-array (list 2 2))
-;; (make-array '(2 2)) works as well.
+;;; Arrays
-; => #2A((0 0) (0 0))
+;;; Both vectors and strings are special-cases of arrays.
-(make-array (list 2 2 2))
+;;; 2D arrays
-; => #3A(((0 0) (0 0)) ((0 0) (0 0)))
+(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)))
-;; Caution- the default initial values are
-;; implementation-defined. Here's how to define them:
+;;; Caution: the default initial values of MAKE-ARRAY are implementation-defined.
+;;; To explicitly specify them:
-(make-array '(2) :initial-element 'unset)
+(make-array '(2) :initial-element 'unset) ; => #(UNSET UNSET)
-; => #(UNSET UNSET)
+;;; To access the element at 1, 1, 1:
-;; And, to access the element at 1,1,1 -
-(aref (make-array (list 2 2 2)) 1 1 1)
+(aref (make-array (list 2 2 2)) 1 1 1) ; => 0
-; => 0
;;; Adjustable vectors
-;; Adjustable vectors have the same printed representation
-;; as fixed-length vector's literals.
+;;; Adjustable vectors have the same printed representation as
+;;; fixed-length vector's literals.
(defparameter *adjvec* (make-array '(3) :initial-contents '(1 2 3)
- :adjustable t :fill-pointer t))
-
+ :adjustable t :fill-pointer t))
*adjvec* ; => #(1 2 3)
-;; Adding new element:
-(vector-push-extend 4 *adjvec*) ; => 3
-
-*adjvec* ; => #(1 2 3 4)
+;;; Adding new elements
+(vector-push-extend 4 *adjvec*) ; => 3
+*adjvec* ; => #(1 2 3 4)
-;;; Naively, sets are just lists:
+;;; Sets, naively, are just lists:
-(set-difference '(1 2 3 4) '(4 5 6 7)) ; => (3 2 1)
-(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)
-(adjoin 4 '(1 2 3 4)) ; => (1 2 3 4)
+(set-difference '(1 2 3 4) '(4 5 6 7)) ; => (3 2 1)
+(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)
+(adjoin 4 '(1 2 3 4)) ; => (1 2 3 4)
-;; But you'll want to use a better data structure than a linked list
-;; for performant work!
+;;; However, you'll need a better data structure than linked lists when working
+;;; with larger data sets
;;; Dictionaries are implemented as hash tables.
-;; Create a hash table
+;;; Create a hash table
+
(defparameter *m* (make-hash-table))
-;; set a value
+;;; Set value
+
(setf (gethash 'a *m*) 1)
-;; Retrieve a value
-(gethash 'a *m*) ; => 1, t
+;;; Retrieve value
+
+(gethash 'a *m*) ; => 1, T
+
+;;; CL expressions have the ability to return multiple values.
+
+(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)
-;; Detail - Common Lisp has multiple return values possible. gethash
-;; returns t in the second value if anything was found, and nil if
-;; not.
+;;; 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.
-;; Retrieving a non-present value returns nil
- (gethash 'd *m*) ;=> nil, 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
-;; Let's handle the multiple return values here in code.
+;;; Let's handle the multiple return values here in code.
-(multiple-value-bind
- (a b)
+(multiple-value-bind (a b)
(gethash 'd *m*)
(list a b))
; => (NIL NIL)
-(multiple-value-bind
- (a b)
+(multiple-value-bind (a b)
(gethash 'a *m*)
(list a b))
; => (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...
+;;;-----------------------------------------------------------------------------
+;;; 3. Functions
+;;;-----------------------------------------------------------------------------
+
+;;; 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}>
-;; Use funcall to call lambda functions
-(funcall (lambda () "Hello World")) ; => "Hello World"
+;;; Use FUNCALL to call anonymous functions
+
+(funcall (lambda () "Hello World")) ; => "Hello World"
+(funcall #'+ 1 2 3) ; => 6
-;; Or Apply
+;;; 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"
-;; De-anonymize the function
-(defun hello-world ()
- "Hello World")
+;;; To name a function, use DEFUN
+
+(defun hello-world () "Hello World")
(hello-world) ; => "Hello World"
-;; The () in the above is the list of arguments for the function
-(defun hello (name)
- (format nil "Hello, ~a" name))
+;;; The () in the definition above is the list of arguments
+(defun hello (name) (format nil "Hello, ~A" name))
(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)
- (if from
- (format t "Hello, ~a, from ~a" name from)
- (format t "Hello, ~a" name)))
-
- (hello "Jim" "Alpacas") ;; => Hello, Jim, from Alpacas
+ (if from
+ (format t "Hello, ~A, from ~A" name from)
+ (format t "Hello, ~A" name)))
-;; And the defaults can be set...
-(defun hello (name &optional (from "The world"))
- (format t "Hello, ~a, from ~a" name from))
+(hello "Jim" "Alpacas") ; => Hello, Jim, from Alpacas
-(hello "Steve")
-; => Hello, Steve, from The world
+;;; The default values can also be specified
-(hello "Steve" "the alpacas")
-; => Hello, Steve, from the alpacas
+(defun hello (name &optional (from "The world"))
+ (format nil "Hello, ~A, from ~A" name from))
+(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.
+;;; Functions also have keyword arguments to allow non-positional arguments
(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")
; => 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
+;;;-----------------------------------------------------------------------------
+
+;;; CL has a sophisticated equality system. Some are covered here.
-;; for numbers use `='
-(= 3 3.0) ; => t
-(= 2 1) ; => nil
+;;; For numbers, use `='
+(= 3 3.0) ; => T
+(= 2 1) ; => NIL
-;; for object identity (approximately) use `eql`
-(eql 3 3) ; => t
-(eql 3 3.0) ; => nil
-(eql (list 3) (list 3)) ; => nil
+;;; For object identity (approximately) use EQL
+(eql 3 3) ; => T
+(eql 3 3.0) ; => NIL
+(eql (list 3) (list 3)) ; => 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
+;;; 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
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;-----------------------------------------------------------------------------
+;;; 5. Control Flow
+;;;-----------------------------------------------------------------------------
;;; Conditionals
@@ -404,71 +462,75 @@ nil ; for false - and the empty list
"this is false") ; else expression
; => "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)
(if (member 'Groucho '(Harpo Groucho Zeppo))
'yep
'nope)
; => '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!"))
((< 2 2) (error "wrong again!"))
(t 'ok)) ; => 'OK
-;; Typecase switches on the type of the value
+;;; TYPECASE switches on the type of the value
(typecase 1
(string :string)
(integer :int))
-
; => :int
-;;; Iteration
-;; Of course recursion is supported:
+;;; Looping
-(defun walker (n)
- (if (zerop n)
- :walked
- (walker (- n 1))))
+;;; Recursion
-(walker 5) ; => :walked
+(defun fact (n)
+ (if (< n 2)
+ 1
+ (* n (fact(- n 1)))))
-;; Most of the time, we use DOLIST or LOOP
+(fact 5) ; => 120
+;;; Iteration
-(dolist (i '(1 2 3 4))
- (format t "~a" i))
+(defun fact (n)
+ (loop :for result = 1 :then (* result i)
+ :for i :from 2 :to n
+ :finally (return result)))
-; => 1234
+(fact 5) ; => 120
-(loop for i from 0 below 10
- collect i)
+(loop :for x :across "abc" :collect x)
+; => (#\a #\b #\c #\d)
-; => (0 1 2 3 4 5 6 7 8 9)
+(dolist (i '(1 2 3 4))
+ (format t "~A" i))
+; => 1234
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; 6. Mutation
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;-----------------------------------------------------------------------------
+;;; 6. Mutation
+;;;-----------------------------------------------------------------------------
-;; Use `setf' to assign a new value to an existing variable. This was
-;; demonstrated earlier in the hash table example.
+;;; Use SETF to assign a new value to an existing variable. This was
+;;; demonstrated earlier in the hash table example.
(let ((variable 10))
(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
-;; Conveyances.
+;;; No more animal classes. Let's have Human-Powered Mechanical
+;;; Conveyances.
(defclass human-powered-conveyance ()
((velocity
@@ -479,14 +541,16 @@ nil ; for false - and the empty list
: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.
+;;; The arguments to DEFCLASS, in order are:
+;;; 1. class name
+;;; 2. superclass list
+;;; 3. slot list
+;;; 4. optional specifiers
-;; 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.
+;;; 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.
(defclass bicycle (human-powered-conveyance)
((wheel-size
@@ -500,7 +564,7 @@ nil ; for false - and the empty list
(defclass recumbent (bicycle)
((chain-type
:accessor chain-type
- :initarg :chain-type)))
+ :initarg :chain-type)))
(defclass unicycle (human-powered-conveyance) nil)
@@ -509,8 +573,7 @@ nil ; for false - and the empty list
:accessor 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)
@@ -532,47 +595,42 @@ nil ; for false - and the empty list
; Readers: AVERAGE-EFFICIENCY
; Writers: (SETF AVERAGE-EFFICIENCY)
-;; Note the reflective behavior available to you! Common Lisp is
-;; designed to be an interactive system
+;;; Note the reflective behavior available. CL was 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
+;;; 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
(defmethod circumference ((object bicycle))
(* 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
-;; of rowers in a canoe is roughly logarithmic. This should probably be set
-;; in the constructor/initializer.
+;;; 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:
+;;; To initialize your instance after CL gets done constructing it:
(defmethod initialize-instance :after ((object canoe) &rest args)
(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))
; => 2.7725887
+;;;-----------------------------------------------------------------------------
+;;; 8. Macros
+;;;-----------------------------------------------------------------------------
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; 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:
+;;; 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
+;;; assembler instincts, we wind up with:
(defmacro while (condition &body body)
"While `condition` is true, `body` is executed.
-
`condition` is tested prior to each execution of `body`"
(let ((block-name (gensym)) (done (gensym)))
`(tagbody
@@ -584,47 +642,47 @@ nil ; for false - and the empty list
(go ,block-name)
,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)
"While `condition` is true, `body` is executed.
-
`condition` is tested prior to each execution of `body`"
`(loop while ,condition
do
(progn
,@body)))
-;; However, with a modern compiler, this is not required; the LOOP
-;; form compiles equally well and is easier to read.
+;;; 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.
+;;; 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.
+;;; 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.
+;;; See Practical Common Lisp and On Lisp for more information on macros.
```
-## Further Reading
+## Further reading
+
+- [Practical Common Lisp](http://www.gigamonkeys.com/book/)
+- [Common Lisp: A Gentle Introduction to Symbolic Computation](https://www.cs.cmu.edu/~dst/LispBook/book.pdf)
-* [Keep moving on to the Practical Common Lisp book.](http://www.gigamonkeys.com/book/)
-* [A Gentle Introduction to...](https://www.cs.cmu.edu/~dst/LispBook/book.pdf)
+## Extra information
-## Extra Info
+- [CLiki](http://www.cliki.net/)
+- [common-lisp.net](https://common-lisp.net/)
+- [Awesome Common Lisp](https://github.com/CodyReichert/awesome-cl)
+- [Lisp Lang](http://lisp-lang.org/)
-* [CLiki](http://www.cliki.net/)
-* [common-lisp.net](https://common-lisp.net/)
-* [Awesome Common Lisp](https://github.com/CodyReichert/awesome-cl)
-## Credits.
+## Credits
Lots of thanks to the Scheme people for rolling up a great starting
point which could be easily moved to Common Lisp.