Fixes based on pkh's comments.

This commit is contained in:
pdn 2013-08-11 10:39:13 -07:00
parent 082dffc697
commit f39aa6adfb

View File

@ -71,16 +71,21 @@ t ; another atom, denoting true.
;;; Symbols ;;; Symbols
'foo ; => FOO 'foo ; => FOO Notice that the symbol is upper-cased automatically.
;; Intern manually creates a symbol from a string.
(intern "AAAA") ; => AAAA (intern "AAAA") ; => AAAA
(intern "aaa") ; => |aaa|
;;; Numbers ;;; Numbers
9999999999999999999999 ; integers 9999999999999999999999 ; integers
#b111 ; binary => 7 #b111 ; binary => 7
#o111 ; octal => 73 #o111 ; octal => 73
#x111 ; hexadecimal => 273 #x111 ; hexadecimal => 273
3.14159 ; floating point 3.14159s0 ; single
3.14159d0 ; double
1/2 ; ratios 1/2 ; ratios
#C(1 2) ; complex numbers #C(1 2) ; complex numbers
@ -93,42 +98,42 @@ t ; another atom, denoting true.
;; You can also call a function manually: ;; You can also call a function manually:
(funcall #'+ 1 2 3) ; => 6 (funcall #'+ 1 2 3) ; => 6
;; Some arithmetic operations ;; Some arithmetic operations
(+ 1 1) ; => 2 (+ 1 1) ; => 2
(- 8 1) ; => 7 (- 8 1) ; => 7
(* 10 2) ; => 20 (* 10 2) ; => 20
(expt 2 3) ; => 8 (expt 2 3) ; => 8
(mod 5 2) ; => 1 (mod 5 2) ; => 1
(/ 35 5) ; => 7 (/ 35 5) ; => 7
(/ 1 3) ; => 1/3 (/ 1 3) ; => 1/3
(+ #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) t ; for true (any not-nil value is true)
nil ; for false nil ; for false - and the empty list
(not nil) ; => t (not nil) ; => t
(and 0 t) ; => 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 simple-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 too!
(concatenate 'string "Hello " "world!") ; => "Hello world!" (concatenate 'string "Hello " "world!") ; => "Hello world!"
;; A string can be treated like a list 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 can be used to format strings:
(format nil "~a can be ~a" "strings" "formatted") (format nil "~a can be ~a" "strings" "formatted")
;; Printing is pretty easy ;; Printing is pretty easy; ~% is the format specifier for newline.
(format t "Common Lisp is groovy. Dude.\n") (format t "Common Lisp is groovy. Dude.~%")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -136,22 +141,26 @@ nil ; for false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; You can create a global (dynamically scoped) using defparameter ;; You can create a global (dynamically scoped) using defparameter
;; a variable name can use any character except: ()[]{}",'`;#|\ ;; a variable name can use any character except: ()[]{}",'`;#|\
;; Dynamically scoped variables should 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. Not very easy to use though... ;; You can also use unicode characters.
(defparameter *foo#\u03BBooo* nil) (defparameter *AΛB* nil)
;; Accessing a previously unassigned variable is an undefined ;; Accessing a previously unbound variable is an
;; behavior (but possible). Don't do it. ;; undefined behavior (but possible). Don't do it.
;; Local binding: `me` is bound to "dance with you" only within the ;; 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 ...). Let always returns the value of the last `form` in the
;; let form. ;; let form.
(let ((me "dance with you")) (let ((me "dance with you"))
me) me)
;; => "dance with you" ;; => "dance with you"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -165,9 +174,12 @@ nil ; for false
: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 ;; ewww) (dog-p *rover*) ; => t ;; ewww)
(dog-name *rover*) ; => "rover" (dog-name *rover*) ; => "rover"
;; Dog-p, make-dog, and dog-name are all created by defstruct!
;;; Pairs ;;; Pairs
;; `cons' constructs pairs, `car' and `cdr' extract the first ;; `cons' constructs pairs, `car' and `cdr' extract the first
;; and second elements ;; and second elements
@ -188,17 +200,21 @@ nil ; for false
;; Can still use `cons' to add an item to the beginning of a list ;; 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 add lists together ;; Use `append' to - surprisingly - append lists together
(append '(1 2) '(3 4)) ; => '(1 2 3 4) (append '(1 2) '(3 4)) ; => '(1 2 3 4)
;; Lists are a very basic type, so there is a wide variety of functionality for ;; Or use concatenate -
(concatenate
;; Lists are a very central type, so there is a wide variety of functionality for
;; them, a few examples: ;; 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
@ -217,60 +233,96 @@ nil ; for false
(make-array (list 2 2)) (make-array (list 2 2))
;; (make-array '(2 2)) works as well.
; => #2A((0 0) (0 0)) ; => #2A((0 0) (0 0))
(make-array (list 2 2 2)) (make-array (list 2 2 2))
; => #3A(((0 0) (0 0)) ((0 0) (0 0))) ; => #3A(((0 0) (0 0)) ((0 0) (0 0)))
;; Caution- the default initial values are
;; implementation-defined. Here's how to define them:
; access the element at 1,1,1, (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) (aref (make-array (list 2 2 2)) 1 1 1)
; => 0 ; => 0
;;; Sets 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
;; for performant work!
;;; Dictionaries are implemented as hash tables. ;;; Dictionaries are implemented as hash tables.
;; Create a hash table ;; Create a hash table
(defparameter m (hash-table)) (defparameter *m* (make-hash-table))
;; set a value ;; set a value
(setf (gethash 'a hash-table 1)) (setf (gethash 'a *m*) 1)
;; Retrieve a value ;; Retrieve a value
(gethash 'a m) ; => 1 (gethash 'a *m*) ; => 1, t
;; Retrieving a non-present value returns a nil ;; Detail - Common Lisp has multiple return values possible. gethash
(gethash m 'd) ;=> nil ;; returns t in the second value if anything was found, and nil if
;; not.
;; Retrieving a non-present value returns nil
(gethash *m* 'd) ;=> nil, nil
;; You can provide a default value for missing keys ;; You can provide a default value for missing keys
(gethash m 'd :not-found) ; => :NOT-FOUND (gethash *m* 'd :not-found) ; => :NOT-FOUND
;; Let's handle the multiple return values here in code.
(multiple-value-bind
(a b)
(gethash 'd *m*)
(list a b))
; => (NIL NIL)
(multiple-value-bind
(a b)
(gethash 'a *m*)
(list a b))
; => (1 T)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 3. Functions ;; 3. Functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Use `lambda' to create anonymous functions. ;; Use `lambda' to create anonymous functions.
;; A function always returns the value of its last expression ;; A function always returns the value of its last expression.
(lambda () "Hello World") ; => #<function> ;; The exact printable representation of a function will vary...
(lambda () "Hello World") ; => #<FUNCTION (LAMBDA ()) {1004E7818B}>
;; Use funcall to call lambda functions ;; Use funcall to call lambda functions
(funcall (lambda () "Hello World")) ; => "Hello World" (funcall (lambda () "Hello World")) ; => "Hello World"
;; Or Apply
(apply (lambda () "Hello World") nil) ; => "Hello World"
;; De-anonymize the function ;; De-anonymize the function
(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 above is the list of arguments for the function
(defun hello (name) (defun hello (name)
(format nil "Hello, ~a " 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
@ -286,6 +338,12 @@ nil ; for false
(defun hello (name &optional (from "The world")) (defun hello (name &optional (from "The world"))
(format t "Hello, ~a, from ~a" name from)) (format t "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 ;; And of course, keywords are allowed as well... usually more
;; flexible than &optional. ;; flexible than &optional.
@ -302,18 +360,18 @@ nil ; for false
;; 4. Equality ;; 4. Equality
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Common Lisp has a sophisticated equality system. ;; Common Lisp has a sophisticated equality system. A couple are covered yere.
;; for numbers use `=' ;; for numbers use `='
(= 3 3.0) ; => t (= 3 3.0) ; => t
(= 2 1) ; => nil (= 2 1) ; => nil
;; for object identity (approximately) use `eq?' ;; for object identity (approximately) use `eql`
(eql 3 3) ; => t (eql 3 3) ; => t
(eql 3 3.0) ; => nil (eql 3 3.0) ; => nil
(eql (list 3) (list 3)) ; => nil (eql (list 3) (list 3)) ; => nil
;; for collections use `equal' ;; for lists, strings, and bit-vectors use `equal'
(equal (list 'a 'b) (list 'a 'b)) ; => t (equal (list 'a 'b) (list 'a 'b)) ; => t
(equal (list 'a 'b) (list 'b 'a)) ; => nil (equal (list 'a 'b) (list 'b 'a)) ; => nil
@ -342,8 +400,8 @@ nil ; for false
;; 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
@ -352,9 +410,9 @@ nil ; for false
;; Of course recursion is supported: ;; Of course recursion is supported:
(defun walker (n) (defun walker (n)
(if (= n 0) (if (zerop 0)
:walked :walked
(walker (1- n)))) (walker (1- n))))
(walker) ; => :walked (walker) ; => :walked
@ -362,12 +420,12 @@ nil ; for false
(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 (loop for i from 0 below 10
collect i) collect i)
; => (0 1 2 3 4 5 6 7 8 9) ; => (0 1 2 3 4 5 6 7 8 9)
@ -380,8 +438,8 @@ nil ; for false
;; demonstrated earlier in the hash table example. ;; demonstrated earlier in the hash table example.
(let ((variable 10)) (let ((variable 10))
(setf variable 10)) (setf variable 2))
; => 10 ; => 2
;; Good Lisp style is to minimize destructive functions and to avoid ;; Good Lisp style is to minimize destructive functions and to avoid
@ -395,34 +453,44 @@ nil ; for false
;; Conveyances. ;; Conveyances.
(defclass human-powered-conveyance () (defclass human-powered-conveyance ()
((velocity ((velocity
:accessor velocity :accessor velocity
:initarg :velocity) :initarg :velocity)
(average-efficiency (average-efficiency
:accessor average-efficiency) :accessor average-efficiency)
: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,
;; 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.
(defclass bicycle (human-powered-conveyance) (defclass bicycle (human-powered-conveyance)
((wheel-size ((wheel-size
:accessor wheel-size :accessor wheel-size
:initarg :wheel-size :initarg :wheel-size
:documentation "Diameter of the wheel.") :documentation "Diameter of the wheel.")
(height (height
:accessor height :accessor height
:initarg :height))) :initarg :height)))
(defclass recumbent (bicycle) (defclass recumbent (bicycle)
((chain-type ((chain-type
:accessor chain-type :accessor chain-type
:initarg :chain-type))) :initarg :chain-type)))
(defclass unicycle (human-powered-conveyance) nil) (defclass unicycle (human-powered-conveyance) nil)
(defclass canoe (human-powered-conveyance) (defclass canoe (human-powered-conveyance)
((number-of-rowers ((number-of-rowers
: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:
@ -438,7 +506,7 @@ nil ; for false
; Direct superclasses: STANDARD-OBJECT ; Direct superclasses: STANDARD-OBJECT
; Direct subclasses: UNICYCLE, BICYCLE, CANOE ; Direct subclasses: UNICYCLE, BICYCLE, CANOE
; Not yet finalized. ; Not yet finalized.
; Direct slots: (defparameter *foo#\u03BBooo* nil) ; Direct slots:
; VELOCITY ; VELOCITY
; Readers: VELOCITY ; Readers: VELOCITY
; Writers: (SETF VELOCITY) ; Writers: (SETF VELOCITY)
@ -450,14 +518,16 @@ nil ; for false
;; designed to be an interactive system ;; designed to be an 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 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))
(* 3.14159 (wheel-size object))) (* pi (wheel-size object)))
;; pi is defined in Lisp already for us!
;; 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 ;; Here's how to initialize your instance after Common Lisp gets done
;; constructing it: ;; constructing it:
@ -488,7 +558,7 @@ nil ; for false
`condition` is tested prior to each execution of `body`" `condition` is tested prior to each execution of `body`"
(let ((block-name (gensym))) (let ((block-name (gensym)))
`(tagbody `(tagbody
(when (not ,condition) (unless ,condition
(go ,block-name)) (go ,block-name))
(progn (progn
,@body) ,@body)
@ -503,13 +573,14 @@ nil ; for false
`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
,@body)) (progn
,@body)))
;; However, with a modern compiler, this is not required; the LOOP ;; However, with a modern compiler, this is not required; the LOOP
;; form compiles equally well and is easier to read. ;; form 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
@ -529,3 +600,5 @@ nil ; for false
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.
- [Paul Khoung](https://github.com/pkhuong) for some great reviewing.