lisp overview
;;;;
;;;; Examples of common lisp
;;;;
;;;; Common Lisp is a language specification, not an actual compiler.
;;;; In what follows I'm using I'm the clisp 2.40 implementation.
;;;;
;;;; Lisp is often programmed and taught from an interactive prompt;
;;;; the lines below therefore often show what would be seen after
;;;; evaluating that line in a comment right after the lisp code.
;;;;
;;;; So if at a real command line you have
;;;;
;;;; $ clisp
;;;; [1]> (+ 1 2)
;;;; 3
;;;; [2]>
;;;;
;;;; Then in this "examples.lisp" file you'd see
;;;;
;;;; (+ 1 2)
;;;; ; 3
;;;;
;;;; In practice there are two common ways to execute a lisp code file :
;;;;
;;;; $ clisp example.lisp # Run the lisp program and then exit.
;;;; or
;;;; $ clisp # Get to the interactive prompt,
;;;; [1]> (load "examples.lisp") # read in the lisp file,
;;;; ;; Loading file ...
;;;; ;; Loaded file ...
;;;; T
;;;; [2]> (invoke_something args) # and run something from the file.
;;;;
;;;; Read about clisp with "man clisp" for command line options,
;;;; saving and restoring its state, and other bells and whistles.
;;;;
;;;; Places to look online for more information :
;;;; * wikipedia common lisp http://en.wikipedia.org/wiki/Common_Lisp
;;;; * GNU CLISP http://clisp.cons.org/
;;;; * Practical Common Lisp http://www.gigamonkeys.com/book/
;;;; * Common Lisp HyperSpec http://www.lisp.org/HyperSpec/FrontMatter
;;;;
;;;; Jim Mahoney, Sep 2007
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; --- eval, quote, first take on numbers, strings, lists ------------
;; The lisp interpreter reads and "evaluates" text expressions,
;; finds their "return value", and prints its representation.
1.2e-3 ; A number (semicolon comments to the end of line)
; 0.0012 ; evaluates to itself.
"Hello" ; So does a string.
; "Hello"
x ; Evaluating an undefined variable (a symbol) is an error.
; EVAL: variable X has no value
; [Condition of type SYSTEM::SIMPLE-UNBOUND-VARIABLE]
(+ 1 2) ; All functions (and operators) are invoked as lists.
; 3
(+ (* 3 4) 7) ; Each element of the list is evaluated.
; 19
(1 2 3) ; Evaluating this list doesn't work.
; EVAL: 1 is not a function name; try using a symbol instead
; [Condition of type SYSTEM::SIMPLE-SOURCE-PROGRAM-ERROR]
(eval (eval 1)) ; You can also invoke eval explicitly.
; 1
(list 1 2 3) ; This works to create a list, since list is a function.
; (1 2 3) ; Note that 1 2 3 are also evaluated, and return themselves.
(quote (1 2 3)) ; quote is special: it does *not* evaluate its argument.
; (1 2 3) ; So this is another way to make this list.
'(1 2 3) ; quote is usually written this way, actually.
; (1 2 3)
'x ; A quoted symbol evals to the symbol.
; x
'(x y z) ; The quote stops all interior evaluation.
; (x y z)
(list (+ 1 2) 3) ; Making a list this way evals the elements.
; (3 3)
'((+ 1 2) 3) ; Making a list this way doesn't.
; ((+ 1 2 3)
;;; ----- symbols and built-in functions ----------------------------------
;; symbols (i.e. variables) have names that can contain *lots* more
;; characters than most cmoputer languages. In fact, almost anything goes.
'(hello a#/?32 0+0+/*?&^>< yes-that-was-a-symbol)
; (HELLO A#/?32 0+0+/*?&^>< YES-THAT-WAS-A-SYMBOL)
;; There are a few special characters that cannot be used in symbol names;
;; lisp call these "read macros" because the do things to what follows
;; as the lisp compiler reads in the stuff to be evaluated.
;; ' quote, e.g. '(1 2) is (quote (1 2)) which evals to (1 2)
;; ( start of list
;; ) end of list
;; ; start of comment
;; , comma (used in macros for some cute eval tricks)
;; ` backquote (also used in macros), e.g. ``(a ,b ,,c)
;; : key args and package delimeters, e.g. (foo :age 3 :color "red")
;; | symbol name delimiter e.g. '|aAbB| gives mixed-case symbol name
;;
;; One other special character can't begin a symbol name, but may be inside.
;; # sharp marks various special input forms, e.g. #Xa34 is hex a34
;; All other characters are legal parts of symbol names,
;; unless the name looks like a number, including
;; * / - + ? & ^ @ : - < > . _ $ ! \
;; There are several common symbol naming conventions.
;; most-symbols-use-dash-between-words
;; *global-variables-typically-have-stars-at-front-and-back*
;; but-global-constants-often-dont-bother-with-stars
;; +though-some-use-pluses-for-global-constants+
;; Also built in are a hundred or so special global symbols, including
;; * first value returned by last top level expression
;; ** first value returned by next to last top level expression
;; *** first value returned by third to last top level expression
;; + ++ +++ ditto for the expressions themselves
;; / // /// ditto for list of the values returned (example?)
;; t true
;; nil false
;; pi 3.14...
;; *package* current package (i.e. loaded namespace)
;; double-float-epsilon smallest double precision number
(+ 0 1)
; 1
(+ 1 1)
; 2
(+ 10 20)
; 30
(list * ** *** + ++ +++ / // ///)
; (30 2 1 (+ 10 20) (+ 1 1) (+ 0 1) (30) (2) (1))
double-float-epsilon
; 1.1102230246251568d-16
*package*
; #<PACKAGE COMMON-LISP-USER>
;; Function and macro names follow the same rules,
;; (Functions manipulate values; macros manipulate functions.)
;; However, in common lisp symbols and functions are in *different* namespaces.
;; This means you can have a function named foo and a symbol named foo
;; which are independent of each other.
;; (This is not true in scheme, a different simpler lisp dialect.)
1
; 1 ; The last expression entered was 1, so the symbol + is 1
(+ + +) ; When this is eval'ed it's treated as (function symbol symbol)
; 2 ; which in this case means (plus 1 1) which is 2.
;; There are hundreds of built-in functions and macros in common lisp.
(third '(a b c d e f))
; C
(sqrt (abs -15))
; 3.8729835
(first '(a b c d)) ; first element of a list
; A
(rest '(a b c d)) ; remaining part of list after removing first element
(B C D)
(car '(a b c d)) ; historical names for first and rest
; A
(cdr '(a b c d))
; (b c d)
(nth 4 '(a b c d e f g)) ; 4th list element (traces down list; slowish)
; E
(nthcdr 4 '(a b c d e f g)) ; 4th cdr
; (E F G)
;;; ---- symbols as pointers ------------------------------
;; Giving a symbol a value in lisp is the same as having it
;; "point" at that value. And "eval" is the same as following the pointer.
;; There is a "set" function which does this, but it's usually awkward
;; to use because it evaluates all its arguments.
(set x 3) ; wrong! This evals x, which isn't defined yet.
; EVAL: variable X has no value
; [Condition of type SYSTEM::SIMPLE-UNBOUND-VARIABLE]
(set 'x 3) ; OK, but 'x gets old. The symbol x now points to value 3.
; 3
x ; evaluating x ...
; 3 ; gives 3.
(* x x) ; And then three times three ..
9 ; is 9.
(setf y 10) ; This is the the more typical way to point y at 10.
; 10 ; setf is "set field"; it works on various named places.
(setf my-list '(a b c d)) ; my-list is (A B C D)
; (A B C D)
(setf (first my-list) 'foo) ; setf here changes the first element
; FOO
my-list ; my-list is now something changed :
; (FOO B C D)
;; But we don't have to point symbols at just numbers.
;; Other symbols (or anything else) works just as well.
(progn ; This function evals each of its args.
(setf one 'two)
(setf two 'three)
(setf three 'one))
; ONE ; Return value is return value of last setf.
(list one two three)
; (TWO THREE ONE) ; What just happened?
;;; ---- functions ------------------------------
;; Sometimes we need more than the name of a function,
;; we need to refer to a function itself, a "bare" or "anonymous" function.
;; For example, mapcar applies a function to every element of a list,
;; bundles up the results into a list, and returns it.
;; (mapcar function_f '(1 2 3)) is ((f 1) (f 2) (f 3))
;; To take the absolute value of a bunch of numbers,
;; you might think this would work, but it won't.
(mapcar abs '(-1 3 -5)) ; Wrong! Here abs is treated as a symbol.
; EVAL: variable ABS has no value
; [Condition of type SYSTEM::SIMPLE-UNBOUND-VARIABLE]
;; Similar to the way 'x is (quote x) is "the symbol x",
;; lisp uses #'abs to mean "the function abs".
(mapcar #'abs '(-1 2 3 10 -20)) ; Right.
; (1 2 3 10 20)
#'abs
; #<SYSTEM-FUNCTION ABS>
;; Defining a named function is done with a macro named defun :
(defun hypotonuse (x y)
(sqrt (+ (* x x) (* y y))))
; HYPOTONUSE
(hypotonuse 3 4)
; 5
#'hypotonuse
; #<FUNCTION HYPOTONUSE (X Y) (DECLARE (SYSTEM::IN-DEFUN HYPOTONUSE))
; (BLOCK HYPOTONUSE (SQRT (+ (* X X) (* Y Y))))>
;; common lisp supports arguments that come in named key,value pairs.
;; In this example, scale and offset are optional named inputs,
;; which have been given default values of 1 and 0 respectively.
;; The first two arguments are required.
;; When this function is evaluated,
;; * the symbols (x1 x2 scale offset) will be bound to the passed values, and
;; * the value returned is the return value of the function body.
(defun doit (x1 x2 &key (scale 1) (offset 0))
(+ offset (* scale (+ x1 x2))))
; DOIT
(doit 3 4) ; run it with default key args
; 7
(doit 3 4 :scale 10) ; run it with scale set to 10
; 70
(doit 3 4 :offset 100) ; run it with offset set to 100
; 107
;; Lisp also has a way to create a function on the fly using lambda.
;; This next line creates a function that doubles its arg
;; and whose "name" is (lambda (x) (* 2 x)), which is applied to 100.
((lambda (x) (* 2 x)) 100)
; 200
;; To refer to the actual function created, we'd again use the #' notation.
;; Here for example is how to double every element in a list.
(mapcar #'(lambda (x) (* 2 x)) '(5 100 23 17))
; (10 200 46 34)
;; Symbol properties may be declared to suppress warnings
;; or increase performance by promising to ony use integers or some such.
(defun foo (x)
"(foo x) ignores x and just returns 1."
(declare (ignore x)) ; (declare (type-name variable))
1)
;;; ---- let, if, when, loop, and programming forms --------------
; coming
;;; ---- sequences, arrays, matrices --------------------
; coming
;;; ---- structures -----------------------------
;; Simplest form :
(defstruct rectangle1
width
height)
;; which defines these functions
;; make-rectangle rectangle-width rectangle-height
(setf r (make-rectangle1 :height 7 :width 5)) ; create a rectangle1
; #S(RECTANGLE :WIDTH 5 :HEIGHT 7)
(setf (rectangle1-width r) 3) ; change its width
; With default values it looks like this.
(defstruct rectangle2
(width 0)
(height 0))
; And with properties set for the structure it looks like this.
; This one has concatenate-name "rect"
; and so creates make-rect rect-width rect-height
(defstruct (rectangle3 (:conc-name rect))
(width 0)
(height 0))
; One property is inheritance: take all the fields from another struct.
(defstruct (thinrect
(:inherit rectangle3
(width 1)))
"Doc string")
;; This last is the same form as the random-vacuum-agent
;; and reactive-vacuum-agents in aima_code/agents/vacuum.lisp
;; from AI: a modern approach :
;;;; -------- start vacuum.lisp ----------------------------------
;;;; Some simple agents for the vacuum world
(defstructure (random-vacuum-agent
(:include agent
(program
#'(lambda (percept)
(declare (ignore percept))
(random-element
'(suck forward (turn right) (turn left) shut-off))))))
"A very stupid agent: ignore percept and choose a random action.")
(defstructure (reactive-vacuum-agent
(:include agent
(program
#'(lambda (percept)
(destructuring-bind (bump dirt home) percept
(cond (dirt 'suck)
(home (random-element '(shut-off forward (turn right))))
(bump (random-element '((turn right) (turn left))))
(t (random-element '(forward forward forward
(turn right) (turn left))))))))))
"When you bump, turn randomly; otherwise mostly go forward, but
occasionally turn. Always suck when there is dirt.")
;;;; -------- end vacuum.lisp ----------------------------------