Artificial
Intelligence

Fall 2007
course
navigation

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 ----------------------------------
http://cs.marlboro.edu/ courses/ fall2007/ai/ lecture_notes/ lisp_overview
last modified Thursday September 13 2007 12:53 pm EDT