%include "default.mgp" %default 1 fore "yellow", bgrad 50 50 300 60 1 "blue" "dark grey" "blue" "blue" "blue" "blue" "blue" "blue" "blue" "blue" "blue" "blue" "blue" "blue" %default 3 fore "white" %tab code font "typewriter", prefix " " %tab smallcode font "typewriter", size 3, prefix " " %tab nocode font "standard", prefix "" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page %center, size 7, font "standard", fore "white", vgap 20 Lisp : Not Bad for a Dead Language %fore "yellow", size 5 Daniel Barlow metacircles Ltd dan@metacircles.com %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page Why Lisp? Eric Raymond's answer LISP is worth learning for a different reason - the profound enlightenment experience you will have when you finally get it. That experience will make you a better programmer for the rest of your days, even if you never actually use LISP itself a lot. %prefix " " -- Eric Raymond %prefix "" %pause So if it's so great, why wouldn't you want to use it a lot? %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page Why Lisp? Peter Norvig's answer, in 1991 Builtin collections Automatic storage management ("garbage collection") Dynamic typing Closures Uniform syntax Interactive development Extensibility History %pause At the time, he didn't mention efficiency. "Lisp is about 1.5 to 4 times faster than Java, and about 10 to 50 times faster than Python. Lisp is probably within 20% to 60% of C/C++ in efficiency on most tasks" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page Why not Lisp? Bad at protecting programmers from each other Poor Unix integration Free Lisps have less-than-stellar graphics support So what is it good for? "Problems which users of other languages consider too hard" Runs best on the server Still has a role in AI (Xerox, SRI) Big in bioinformatics ITA/Orbitz, Yahoo! Store, Hotdispatch Drawing trees %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page 1960s : Lisp 1, 1.5 1956: John McCarthy sets out to design the first Lisp compiler "... algebraic list processing language for AI work" starts by hand-assembling basic functions Lisp 1: Autumn 1960 "Recursive functions of symbolic expressions and their computation by machine, part I" Showed the "universal LISP function" eval[a,b] S R Russell noticed that eval would work as an interpreter, and hand-coded it Shazaam! Lisp 1.5: 1960 - 1965 Further improvements %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page 1970s : Xerox and MIT diverge MacLisp (nothing to do with the Macintosh), 1970s Functions with variable numbers of arguments Macros, arrays, fast arithmetic First good compiler. Emphasis on execution speed Interlisp, 1970s LOOP, ancient predecessor of Scheme, late 1970s Gerald Sussman and Guy Steele Lexical scoping, closures, first-class continuations, simpler syntax OOP, late 1970s At MIT, Flavors At Xerox, LOOPS and later Common LOOPS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page 1970s : Lisp machines Early 1970s, Peter Deutsch & Daniel Bobrow did Lisp on Xerox Alto using microcode as bytecode interpreter Richard Greenblatt started his own project at MIT Xerox D-series machines got Interlisp-D MacLisp fed into Lisp Machine Lisp on the MIT Lispms Commercial Lisp machines from Xerox, Symbolics and LMI availabe by 1981 Symbolics hire all the hackers from MIT, causing Stallman to start writing GNU %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page 1980s : Standardization, AI Bubble SPICE Lisp: CMU project started in 1980 Franz Lisp: First Lisp to run on Unix machines Common Lisp The Language, April 1981 The splintered MacLisp community, worried that DARPA might switch to Interlisp, standardize Ideas from Scheme (lexical scope) also adopted ANSI standardisation, 1986-1994 Based on Common Lisp The Language, plus CLOS AI Boom, mid-late 80s. AI Bust, shortly following Lisp tainted by AI's failure, became unfashionable Besides, it was still too big and too slow %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page 1990 - present day. Rest of world catches up ANSI standard released 1994 Ideas from Lisp (GC, closures) start appearing in mainstream languages Hardware gets cheaper. Lisp does not get noticeably more greedy Now practical to run a full-featured Lisp on even quite cheap machines Free Lisp community gets its act together %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page Survivors ANSI Common Lisp "Industrial strength" A political compromise Scheme "The Right Thing" but too small for any useful work Emacs Lisp is inspired by MacLisp Autolisp, used in Autocad Dynamically scoped rep, used in sawmill^Wsawfish %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page Implementations On Unix, SBCL, CMUCL, CLISP, OpenMCL (PPC) are all "free as in speech" Allegro CL and Xanalys Lispworks have "free as in beer" downloadable versions Avoid GCL On Windows Allegro CL, Xanalys Lispworks, Corman Lisp, CLISP On the Macintosh MCL for OS9, also recently announced for MacOS X OpenMCL on OSX, but pretty graphics still in development %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page Getting started You will need: A Lisp environment An editor with Lisp support at least paren matching and indentation if you can tolerate Emacs, ILISP is a big win Optionally, a copy of the Hyperspec Running Lisp The Read/Eval/Print Loop (REPL) READ the input EVALuate the expression PRINT the answer LOOP around to do it again %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page What does READ actually do? It doesn't just read the string and pass that to EVAL It parses the string into structured objects in memory for EVAL to act on So you can programmatically create your own objects and evaluate them too ... more later Or you can use the same READ to create objects for other purposes than evaluation (e.g. data files) What kind of objects? Strings, Symbols, Numbers, Lists, Arrays, etc But, if we're going to call EVAL, typically a lot of lists &code "hello world" foo 2/3 (1 2 3) #(1 2 3) 2/5 #xa 1.3 #c(1 2) 2.999d8 1073741822000 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page The Route of all EVAL : what do we do with these objects? Not all objects that READ can make are valid Lisp programs A Lisp program is made of forms. A form is usually a list with a symbol in its first position The symbol might name a special operator or macro, or a function It looks the same either way, but argument evaluation is different &code (+ 1 2) => 3 (or t nil) => T (if (= (+ 2 2) 4) "OK" (error "Universe broken, reinstall")) => "OK" &nocode %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page Iteration and control flow Predicates return T (true) or NIL (false) Actually they return non-NIL (true) or NIL (false) eq, eql, equal, =, string= Avoid eq. Probably avoid equal for complex data structures Don't compare floating-point numbers for equality if, cond &smallcode (if condition then else) &smallcode (if (eql 2 2) (format t "hello") (format t "goodbye")) &nocode progn - sequencing &smallcode (progn a b) ;; do a then b &nocode dolist, dotimes, mapcar &smallcode (dolist (i (list 1 2 "hello" 4)) (princ i)) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page Defining functions &code (defun double (x) (* 2 x)) (double 2) => 4 (defun greet (name time-of-day &key with-vigour) "Greet NAME according to TIME-OF-DAY, optionally WITH-VIGOUR" (format t "Good ~A, ~A~A~%" time-of-day name (if with-vigour "!" "."))) (greet "Compsoc" "Evening" :with-vigour t) Good Evening, Compsoc! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page Sequences (collections) "Everything is a list" is untrue, as we've seen already but they are convenient, because we represent code with them Lists are actually made up of CONSes. A cons cell is like a struct with two pointers car and cdr as elements &code struct cons { %prefix "" struct cons *car, *cdr; %prefix " " } &nocode We make lists out of them by chaining CDRs together &code (cons 1 (cons 2 (cons 3 nil))) => (1 2 3) &nocode We can also use conses for binary trees etc %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page More sequences Vectors provide O(1) access. They may be specialised (e.g. strings) Functions for dealing with sequences: elt, position, subseq, reverse QUOTE stops evaluation of its argument. QUASIQUOTE similar but has an 'escape' &code '("this" is valid 1.23 "data" but not (code)) => ("this" IS VALID 1.23 "data" BUT NOT (CODE)) `("this" is valid data ,(+ 1 2 3) "with embedded code") => ("this" IS VALID DATA 6 "with embedded code") %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page (Marginally) complex data structures: Cheesy HTML generation HTML is made of nested sequences too ... &smallcode (defun to-html (element) (if (listp element) (let ((element-name (first element)) (element-content (rest element))) (format nil "<~A>~{~A~}~A>" element-name (mapcar #'to-html element-content) element-name)) (format nil "~A" element))) (let ((my-html `(html (head (title "Document title")) (body (h1 "Hello") (p "1 + 2 + 3 = " ,(+ 1 2 3)))))) (to-html my-html)) => "
Here is a paragraph6
" &nocode %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page Programs are complex data structures too: Macros Macros are functions which take Lisp forms as arguments, and turn them into other Lisp forms. They run before the form is compiled or evaluated &code (defmacro double (x) (list '* x 2)) (double 4) => 8 &nocode Quasiquotation makes for more readable macros &code (defmacro double (x) `(+ ,x ,x)) &nocode This has a bug: x will get evaluated twice We could have used a function anyway. If you can, do %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page More macros A common idiom for robustly allocating and freeing a scarce resource &smallcode ;;; unwind-protect is like Java's try/finally. The body form is ;;; evaluated, then the cleanup forms are evaluated even if the body ;;; caused some kind of error (unwind-protect (let ((my-foo (allocate-a-foo))) (do-stuff)) (free-foo my-foo)) ;;; but we don't want to type this every time - we'd rather just do (with-foo (my-foo) (do-stuff)) ;;; and by defining a suitable with-foo macro, we can extend the language ;;; to make this possible (defmacro with-foo ((foo-name) &body forms) `(let ((,foo-name (allocate-a-foo))) (unwind-protect (progn ,@forms) (free-foo ,foo-name)))) &nocode %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page CLOS: The Common Lisp Object System As compared to fashionable object systems: Multiple specialisation No need for Visitor pattern Multiple inheritance Little support for encapsulation You can do evil things with symbols, but why make life difficult? &smallcode (defclass animal () ((name :accessor animal-name :initarg :name))) (defclass dog (animal) ((licence-number :accessor dog-licence-number :initarg :number))) (make-instance 'dog :name "Fido" :number 12345) => #