summaryrefslogtreecommitdiffhomepage
path: root/common-lisp.html.markdown
diff options
context:
space:
mode:
Diffstat (limited to 'common-lisp.html.markdown')
-rw-r--r--common-lisp.html.markdown604
1 files changed, 604 insertions, 0 deletions
diff --git a/common-lisp.html.markdown b/common-lisp.html.markdown
new file mode 100644
index 00000000..24b6947f
--- /dev/null
+++ b/common-lisp.html.markdown
@@ -0,0 +1,604 @@
+---
+
+language: commonlisp
+filename: commonlisp.lisp
+contributors:
+ - ["Paul Nathan", "https://github.com/pnathan"]
+---
+
+ANSI Common Lisp is a general purpose, multi-paradigm programming
+language suited for a wide variety of industry applications. It is
+frequently referred to 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/).
+
+
+
+```commonlisp
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; 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.
+
+(+ 1 2 3 4) ; an s-expression
+
+'(4 :foo t) ;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|
+
+;;; Numbers
+9999999999999999999999 ; integers
+#b111 ; binary => 7
+#o111 ; octal => 73
+#x111 ; hexadecimal => 273
+3.14159s0 ; single
+3.14159d0 ; double
+1/2 ; ratios
+#C(1 2) ; 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.
+'(+ 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!"
+
+;; 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")
+
+;; Printing is pretty easy; ~% is the format specifier for newline.
+(format t "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
+(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*) ; => 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
+(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)
+
+;; Can still use `cons' to add an item to the beginning of a list
+(cons 4 '(1 2 3)) ; => '(4 1 2 3)
+
+;; Use `append' to - surprisingly - append lists together
+(append '(1 2) '(3 4)) ; => '(1 2 3 4)
+
+;; Or use concatenate -
+
+(concatenate
+
+;; 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
+(some #'oddp '(1 2 3 4)) ; => T
+(butlast '(subject verb object)) ; => (SUBJECT VERB)
+
+
+;;; Vectors
+
+;; Vectors 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)
+
+;;; Arrays
+
+;; Both vectors and strings are special-cases of arrays.
+
+;; 2D arrays
+
+(make-array (list 2 2))
+
+;; (make-array '(2 2)) works as well.
+
+; => #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:
+
+(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
+
+;;; Naively, sets 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)
+
+;; 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 *m* 'd) ;=> nil, nil
+
+;; You can provide a default value for missing keys
+(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
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; 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
+(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))
+
+(hello "Steve") ; => "Hello, Steve"
+
+;; 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
+
+;; And the defaults can be set...
+(defun hello (name &optional (from "The world"))
+ (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
+;; flexible than &optional.
+
+(defun generalized-greeter (name &key (from "the world") (honorific "Mx"))
+ (format t "Hello, ~a ~a, from ~a" honorific name from))
+
+(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 yere.
+
+;; 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 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
+
+(if t ; 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 '(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 ((> 2 2) (error "wrong!"))
+ ((< 2 2) (error "wrong again!"))
+ (t 'ok)) ; => 'OK
+
+;; Typecase switches on the type of the value
+(typecase 1
+ (string :string)
+ (integer :int))
+
+; => :int
+
+;;; Iteration
+
+;; Of course recursion is supported:
+
+(defun walker (n)
+ (if (zerop n)
+ :walked
+ (walker (1- n))))
+
+(walker) ; => :walked
+
+;; Most of the time, we use DOLIST or LOOP
+
+
+(dolist (i '(1 2 3 4))
+ (format t "~a" i))
+
+; => 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.
+
+(let ((variable 10))
+ (setf variable 2))
+ ; => 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.
+
+(defclass human-powered-conveyance ()
+ ((velocity
+ :accessor velocity
+ :initarg :velocity)
+ (average-efficiency
+ :accessor average-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.
+
+(defclass bicycle (human-powered-conveyance)
+ ((wheel-size
+ :accessor wheel-size
+ :initarg :wheel-size
+ :documentation "Diameter of the wheel.")
+ (height
+ :accessor height
+ :initarg :height)))
+
+(defclass recumbent (bicycle)
+ ((chain-type
+ :accessor chain-type
+ :initarg :chain-type)))
+
+(defclass unicycle (human-powered-conveyance) nil)
+
+(defclass canoe (human-powered-conveyance)
+ ((number-of-rowers
+ :accessor number-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.
+(defparameter *foo#\u03BBooo* nil) ; 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
+
+(defmethod circumference ((object bicycle))
+ (* 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
+;; 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:
+
+(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...
+
+(average-efficiency (make-instance 'canoe :number-of-rowers 15))
+; => 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:
+
+(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)))
+ `(tagbody
+ (unless ,condition
+ (go ,block-name))
+ (progn
+ ,@body)
+ ,block-name)))
+
+;; 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.
+
+;; 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.
+
+
+## Further Reading
+
+[Keep moving on to the Practical Common Lisp book.](http://www.gigamonkeys.com/book/)
+
+
+## Credits.
+
+Lots of thanks to the Scheme people for rolling up a great starting
+point which could be easily moved to Common Lisp.
+
+- [Paul Khoung](https://github.com/pkhuong) for some great reviewing.