This is a Lisp page, written Sat Jan 26 19:43:41 PST 2008.
The SBCL function save-lisp-and-die can be used to snapshot the current state of the virtual machine and write that to disk. Optionally, if the :executable t flag is added, the LISP interpreter can be added to the snapshot file. The result is a (large) stand alone executable that can be run without needing the SBCL environment.
For example, here's a file misc/search1-exe.lisp that builds a stand-alone executable for the NOVA system.
(load "make.lisp") (load "apps/search1.lisp") (defun search1-and-quit () (search1) (quit)) (save-lisp-and-die "tmp/search1" :toplevel 'search1-and-quit :executable t )
Note that:
If this is loaded into LISP, then the system is made and saved to disk. Then...
cd tmp ./search1 --noinformwill run the file tmp/search1.
That's the good news. The bad news is that the executable contains all of LISP. The example above generated a 24MB file from less than 2000 lines of LISP. Oh well.
This is a Lisp page, written Sun Jan 20 14:29:21 PST 2008.
Globals are good; they stop you having to pass around big parameter lists.
Globals are bad; side-effects from one function can ruin another.
With LISP's local-global trick you can have it both ways. A global is copied to a local temporary that can be referenced by called functions called from some master function. BUT, and here's the the trick, all changes made by this sub-functions just go away when they terminate.
Here's how it works. First, define global parameter:
(defparameter *x* 1)
Now, define a main function that calls some worker function.
(defun main() (format t "before ~a~%" *x*) (worker) (format t "after ~a~%" *x*) )
The worker changes the scope of the global using the "&optional" command, then calls some underlings to get the job done.
(defun worker (&optional (*x* *x*))
(underling)
)
(defun underling ()
(format t "during1 ~a~%" *x*)
(dotimes (i 3)
(incf *x* i)
(format t "during2 ~a~%" *x*)))
Now, when the worker is call, all the changes made by the underlings disappear when the work is done. Observe in the following how the underling makes many changes to "*x*" which are gone when the worker terminates:
CL-USER> (main) before 1 during1 1 during2 1 during2 2 during2 4 after 1
This is a Lisp page, written Sat Jan 19 15:21:54 PST 2008.
LISP functions can accept any number of arguments after the "&rest" keyword. So, to add up any number of "nums":
(defun sum (&rest nums)
(let ((sum 0))
(dolist (one nums sum)
(incf sum one))))
E.g.
(SUM 1 1 1 1 2 2 4 100) => 112
And, if you want the mean value, divide the sum by the number of items in the list:
(defun mean (&rest nums)
(let ((sum 0)
(n 0))
(dolist (one nums (/ sum n))
(incf n)
(incf sum one))))
E.g.
(MEAN 1 1 1 1 2 2 4 100) => 14
LISP functions can also return more than one value using the "values" keyword. Here, we compute mean and standard deviation of a set of numbers.
(defun mean-sd (&rest nums)
(let ((sum 0)
(n 0)
(sumSq 0))
(labels ((mean () (/ sum n))
(sd () (sqrt (/ (- sumSq(/ (* sum sum) n)) (- n 1) ))))
(dolist (one nums)
(incf n)
(incf sum one)
(incf sumSq (* one one)))
(values
(mean)
(sd)))))
E.g.
(MEAN-sd 1 1 1 1 2 2 4 100) => 14 34.764515
We can use the same kind of function to return the median and the "spread" of a set of numbers. The median value is the point at which half the values lie below it:
This list also returns "spread", i.e. the difference between the 50% and 75% value. "Spread" (not the official technical name) is useful for measuring the expected deviation from the median.
(defun median (&rest nums)
"return 50% and (75-50)% values"
(let* ((n1 (sort nums #'<))
(l (length n1))
(mid (floor (/ l 2)))
(midval (nth mid n1))
(75percent (nth (floor (* l 0.75)) n1))
(50percent (if (oddp l)
midval
(mean midval (nth (- mid 1) n1)))))
(values
50percent
(- 75percent
50percent))))
E.g.
(MEDIAN 1 1 1 1 2 2 4 100) => 3/2 5/2
This is a Lisp page, written Sat Jan 19 08:35:31 PST 2008.
In this tutorial, we show how to speed up loading of LISP code. For the case study shown here, 700 lines of lisp were loaded slowly, in 0.975 seconds, then quickly in 0.175 seconds (over five times faster). Obviously, that speed up factor is system dependent.
(Oh, and in case there are there are typos in the following, the on-line code is here.)
"Maker" is a lisp function that, optionally, pre-processes textual .lisp files into a binary fast load .fasl format.
#+SBCL (DECLAIM (SB-EXT:MUFFLE-CONDITIONS CL:STYLE-WARNING))
(defun maker ( &key files
faslp ; if nil, just load, don't fasl
forcep ; always force a re-compile?
)
(labels ; some one-liners for compiling and loading files
((filename (x y) (string-downcase (format nil "~a.~a" x y)))
(src (f) (filename f "lisp"))
(bin (f) (filename f "fasl"))
(newerp (f1 f2 ) (> (file-write-date f1)
(file-write-date f2)))
(compile? (src bin) (or forcep
(not (probe-file bin))
(newerp src bin)))
(update (f) (if (compile? (src f) (bin f))
(compile-file (src f))))
(cake (f) (update f) (load (bin f)))
(loader (f) (format t ";;;; FILE: ~a~%" f) (load f))
(make1 (f) (if faslp
(cake f)
(loader (src f)))))
(mapc #'make1 files)))
In this first example, we turn off fasl pre-processing and load stuff the slow way:
(defun make-slow () "list your files to load" (maker :files '( macros eg lib guess-db config guess coc-lib demos )))
In this example, we enable fasl pre-processing. Note that a new file is created in the current directory and, if the .lisp file ever has a new change date than the .lisp file, fasl pre-processing is repeated.
(defun make-fast ()
"list your files to load"
(maker :faslp t
:files '(
macros
eg
lib
guess-db
config
guess
coc-lib
demos
)))
In the usual case, only a few source files are ever changed so fasl pre-processing is required for only a small part of the system.
In the worst case, all the files are loaded the slow way.
In the best case, everything has been fasl-ed so "compilation" becomes "just load the fasls".
The following times just compare the worst case with the best case:
(time (make-slow)) Evaluation took: 0.975 seconds of real time 0.912261 seconds of user run time 0.050491 seconds of system run time [Run times include 0.103 seconds GC run time.] 0 calls to %EVAL 0 page faults and 44,846,872 bytes consed. (MACROS EG LIB GUESS-DB CONFIG GUESS COC-LIB DEMOS)Note that the worst case took 0.975 seconds and the best case, shown below, tool 0.175 seconds.
(time (make-fast)) Evaluation took: 0.175 seconds of real time 0.164378 seconds of user run time 0.005954 seconds of system run time 0 calls to %EVAL 0 page faults and 9,153,928 bytes consed. (MACROS EG LIB GUESS-DB CONFIG GUESS COC-LIB DEMOS)
This is a Lisp page, written Fri Jan 18 10:11:32 PST 2008.
Let sum up the first 1,000 integers.
Solution 1: recursion with funky initializations in variable list:
(defun n1 (&optional (x 1000))
(if (< x 0)
0
(+ x (n1 (- x 1)))))
Solution 2: recursion but using helper function called by the main worker with defaults:
(defun n2 ()
(labels
((n0 (x)
(if (< x 0)
0
(+ x (n0 (- x 1))))))
(n0 1000)))
Solution 3: no recursion:
(defun n3 ()
(do* ((x 1000 (1- x))
(sum x (+ sum x)))
((< x 0) sum)))
Timings:
(defun ns ()
(let ((r 100000))
(print t) (time (dotimes (i r) t))
(print 'n1) (time (dotimes (i r) (n1)))
(print 'n2) (time (dotimes (i r) (n2)))
(print 'n3) (time (dotimes (i r) (n3)))))
Results:
CL-USER> (ns) T Evaluation took: 0.0 seconds of real time 1.03e-4 seconds of user run time 2.e-6 seconds of system run time N1 Evaluation took: 3.167 seconds of real time 3.154306 seconds of user run time 0.002845 seconds of system run time N2 Evaluation took: 2.818 seconds of real time 2.812621 seconds of user run time 0.001603 seconds of system run time N3 Evaluation took: 0.705 seconds of real time 0.703598 seconds of user run time 5.08e-4 seconds of system run time
Conclusions:
This is a Lisp page, written Fri Jan 18 18:45:53 PST 2008.
"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil."
For example, say there is some code "(demo456)" that does "something". In SBCL, this is how we could learn where the time goes.
First, we need a list of functions to profile:
(defun profiles () (sb-profile:profile ?bag ?dr ?elt ?em ?num ?one-a ?one-b ... ))
Hint: to get a list of all functions in the lisp code in a directory, run
grep defun *.lisp | gawk '{print $2}'
Then add this code to your lisp interpreter:
(defun watch (code) (sb-profile:unprofile) (sb-profile:reset) (profiles) (eval code) (sb-profile:report) (sb-profile:unprofile) )
Then, "watch" something:
(watch '(demo456))
This outputs something like this:
CL-USER> (watch '(demo456))
WARNING: ignoring undefined function @DR
seconds | consed | calls | sec/call | name
----------------------------------------------------------
0.143 | 2,781,184 | 170,000 | 0.000001 | EM2EFFORT
0.101 | 2,813,952 | 170,000 | 0.000001 | EM2CIN
0.100 | 2,658,304 | 170,000 | 0.000001 | EM2DIN
0.067 | 2,678,784 | 170,000 | 0.0000004 | EM2RIN
0.065 | 413,696 | 50,000 | 0.000001 | SF2EFFORT
0.033 | 348,160 | 50,000 | 0.000001 | SF2CIN
0.027 | 172,032 | 30,000 | 0.000001 | DR2ROUT
0.024 | 192,512 | 30,000 | 0.000001 | DR2COUT
0.023 | 421,888 | 50,000 | 0.0000005 | SF2RIN
0.021 | 401,408 | 50,000 | 0.0000004 | SF2DIN
0.008 | 167,936 | 10,124 | 0.000001 | MY-RANDOM
0.001 | 0 | 28 | 0.000033 | GETA
0.001 | 0 | 5 | 0.000180 | ?SF
0.000 | 0 | 1 | 0.000000 | POINT-TO-LINE
0.000 | 0 | 1 | 0.000000 | LINE-Y
0.000 | 0 | 1 | 0.000000 | INIT-DB
0.000 | 0 | 27 | 0.000000 | GUESS
0.000 | 172,032 | 30,000 | 0.000000 | DR2DOUT
0.000 | 0 | 1 | 0.000000 | COCOMO-DEFAULTS
0.000 | 0 | 1 | 0.000000 | ?ONE-B
0.000 | 0 | 1 | 0.000000 | ?ONE-A
0.000 | 0 | 17 | 0.000000 | ?EM
0.000 | 0 | 25 | 0.000000 | ?ELT
0.000 | 0 | 3 | 0.000000 | ?DR
0.000 | 0 | 25 | 0.000000 | ?BAG
----------------------------------------------------------
0.613 | 13,221,888 | 980,260 | | Total
estimated total profiling overhead: 4.69 seconds
overhead estimation parameters:
1.8e-8s/call, 4.784e-6s total profiling, 2.264e-6s internal profiling
These functions were not called:
?NUM ?QUANTITY AS-LIST COC-LIB1 DEMO DEMO-GUESS DEMO-GUESS1 DEMO123 DEMOF
EG EG0 EGS GUESS-DEMO-ALL GUESS0A GUESS0B GUESS0C GUESS0D GUESS0E GUESS0F
GUESS0G HINGED-LINE HINGED-LINE-COQUALMO MAKE MAKER MY-COMMAND-LINE
MY-GETENV PIVOTED-LINE SYM-PRIM ZAP ZAPS
NIL
CL-USER>
Looking at the above, if we can speed up "em2effort", "em2cin" and "em2din" then we'd halve the runtime.
This is a Lisp page, written Fri Jan 18 20:01:28 PST 2008.
Previously, we described a simple method to profile selected functions in SBCL Lisp.
But what about the related task of profiling all your code? The code http://unbox.org/wisp/var/timm/08/ai/src/profile.lisp illustrates one method.
That code contains a list of all symbols in a standard release of Common LISP and SBCL:
(defparameter *lisp-funs* '(
*
*
**
***
+
+
++
+++
-
-
/
/
//
///
1+
1-
<
<=
=
>
>=
abort
abs
acons
acos
etc
))
(defun my-funs ()
(let ((out '()))
(do-symbols (s)
(if (and (fboundp s)
(find-symbol (format nil "~a" s) *package*)
(not (member s *lisp-funs*)))
(push s out)))
out))
With "my-funs", we can write a "watch" macro that wraps the SBCL profiling calls:
(defmacro watch (code)
`(progn
(sb-profile:unprofile)
(sb-profile:reset)
(sb-profile:profile ,@(my-funs))
(eval ,code)
(sb-profile:report)
(sb-profile:unprofile)
t)
)
With all the above, then we can profile all the functions called from some high-level "(main)" function, as follows:
(watch (main))
The result is a standard SBCL profiler output. Note that, in the following, the "!" function takes 0.447/0.707 (i.e. over half) the run time. So if we are going to optimize anything, optimize "!".
CL-USER> (watch (main))
seconds | consed | calls | sec/call | name
------------------------------------------------------------
0.447 | 0 | 990,001 | 0.0000005 | !
0.105 | 6,819,840 | 170,000 | 0.000001 | EM2EFFORT
0.073 | 6,795,264 | 170,000 | 0.0000004 | EM2RIN
0.027 | 6,778,880 | 170,000 | 0.0000002 | EM2CIN
0.020 | 1,585,152 | 50,000 | 0.0000004 | SF2CIN
0.016 | 1,630,208 | 50,000 | 0.0000003 | SF2DIN
0.012 | 6,742,016 | 170,000 | 0.0000001 | EM2DIN
0.006 | 946,176 | 30,000 | 0.0000002 | DR2ROUT
0.001 | 0 | 14 | 0.000067 | MAKE-R15
0.001 | 8,192 | 1 | 0.000539 | COCOMO-DEFAULTS
0.000 | 0 | 5 | 0.000000 | MAKE-SFS
0.000 | 0 | 1 | 0.000000 | LINE-Y
0.000 | 0 | 27 | 0.000000 | ?
0.000 | 0 | 1 | 0.000000 | INIT-DB
0.000 | 0 | 5 | 0.000000 | MAKE-R16
0.000 | 0 | 7 | 0.000000 | MAKE-RIN+
0.000 | 1,695,744 | 50,000 | 0.000000 | SF2EFFORT
0.000 | 0 | 1 | 0.000000 | MAKE-R26
0.000 | 0 | 9 | 0.000000 | MAKE-EM-
0.000 | 0 | 6 | 0.000000 | MAKE-DIN+
0.000 | 0 | 1 | 0.000000 | ?ONE-B
0.000 | 0 | 1 | 0.000000 | MAKE-ONE-A
0.000 | 0 | 27 | 0.000000 | GUESS
0.000 | 0 | 25 | 0.000000 | ?ELT
0.000 | 0 | 5 | 0.000000 | MAKE-DSF
0.000 | 974,848 | 30,000 | 0.000000 | DR2DOUT
0.000 | 0 | 34 | 0.000000 | MAKE-EM
0.000 | 0 | 25 | 0.000000 | ?BAG
0.000 | 0 | 6 | 0.000000 | MAKE-DR
0.000 | 0 | 10 | 0.000000 | MAKE-RIN-
0.000 | 0 | 5 | 0.000000 | MAKE-RSF
0.000 | 0 | 3 | 0.000000 | ?DR
0.000 | 0 | 1 | 0.000000 | POINT-TO-LINE
0.000 | 0 | 3 | 0.000000 | MAKE-RDR
0.000 | 0 | 1 | 0.000000 | DEMO456
0.000 | 0 | 1 | 0.000000 | MAKE-LINE
0.000 | 0 | 3 | 0.000000 | MAKE-R25
0.000 | 0 | 3 | 0.000000 | MAKE-DDR
0.000 | 0 | 5 | 0.000000 | MAKE-CSF
0.000 | 0 | 10 | 0.000000 | MAKE-SF
0.000 | 0 | 6 | 0.000000 | MAKE-CIN+
0.000 | 0 | 11 | 0.000000 | MAKE-CIN-
0.000 | 0 | 28 | 0.000000 | GETA
0.000 | 1,482,752 | 50,000 | 0.000000 | SF2RIN
0.000 | 0 | 5 | 0.000000 | ?SF
0.000 | 8,192 | 17 | 0.000000 | ?EM
0.000 | 0 | 8 | 0.000000 | MAKE-EM+
0.000 | 0 | 2 | 0.000000 | MAKE-NUM
0.000 | 0 | 1 | 0.000000 | ?ONE-A
0.000 | 958,464 | 30,000 | 0.000000 | DR2COUT
0.000 | 0 | 3 | 0.000000 | MAKE-CODR
0.000 | 0 | 1 | 0.000000 | MAKE-ONE-B
0.000 | 24,076,288 | 1 | 0.000000 | DEMO456A
0.000 | 0 | 25 | 0.000000 | COCO
0.000 | 0 | 2 | 0.000000 | MAKE-R36
0.000 | 0 | 11 | 0.000000 | MAKE-DIN-
0.000 | 0 | 1 | 0.000000 | MAKE-DB
0.000 | 155,648 | 10,124 | 0.000000 | MY-RANDOM
------------------------------------------------------------
0.707 | 60,657,664 | 1,970,493 | | Total
This is a Lisp | Fun | Image page, written Thu Dec 6 10:11:34 PST 2007.
This is a Lisp | Image page, written Mon Dec 3 19:16:46 PST 2007.
This is a Lisp page, written Mon Dec 3 19:07:15 PST 2007.
Peter Seibe's excellent text Practical Common LISP.
Lots of good material from Marty Hall.
This is a News | Lisp page, written Mon Dec 3 08:03:47 PST 2007.
After much sweat, I have given up trying to run Norvig's code using his support tools.
The code in the pages of the textbook is fine- but the support tools seem to be written for quirky older versions of LISP.
So now, to run Norvig's stuff, I carefully paste in the functions one-by-one and only those from the pages of the textbook. Slower, yes, but at least I understand the code that I load.
This is a Lisp page, written Tue Nov 27 18:34:17 PST 2007.
Lots of good material from Marty Hall.
This is a Lisp | Start page, written Fri Nov 23 09:09:44 PST 2007.

To get a working (freely available) LISP system, look for SBCL (best) or CLISP (ok)
Please don't use any SCHEME dialect. SCHEME is a really great language but it never ran as fast as SBCL
Then try to run and understand all the examples in the textbook, Part I: Introduction to Common Lisp
(By the way, understanding these examples is your project1 assignment for class. So doing this won't waste any of your time.).
Note: source code for the above can be found at here.
This is a Lisp page, written Fri Nov 23 09:14:56 PST 2007.
If you are feeling adventurous, try reading Graham's excellent text On Lisp.
Graham is the guy responsible for the recent resurgence in LISP (sold his dot-com to Yahoo for $X0,000,000 that was based on LISP). So take careful note of all he says.
This is a Lisp | Emacs | Start page, written Fri Nov 23 09:05:43 PST 2007.
S.L.I.M.E. = superior LISP interaction mode for emacs.
It is my recommendation for writing, running, and debugging LISP code (though some people prefer the CUSP SBCL plugin for ECLIPSE).
If you want to get started on slime on a CSEE Linux machine, edit your $HOME/.emacs and add these lines.
(setq inferior-lisp-program "/usr/bin/sbcl --noinform") (add-to-list 'load-path "/usr/share/common-lisp/source/slime/") ;; this path is WVU CSEE specific (setq slime-path "/usr/share/common-lisp/source/slime/") ;; this path is WVU CSEE specific (require 'slime) (slime-autodoc-mode) (slime-setup) (add-hook 'lisp-mode-hook (lambda () (slime-mode t) (local-set-key "\r" 'newline-and-indent) (setq lisp-indent-function 'common-lisp-indent-function) (setq indent-tabs-mode nil))) (global-set-key "\C-cs" 'slime-selector)
Then fire up emacs and type M-x slime. After that, any .lisp file you edit will have some cool LISP bindings (see http://common-lisp.net/project/slime/doc/html/Compilation.html#Compilation).
This is a Syllabus | Lisp page, written Thu Nov 22 21:10:17 EST 2007.
Peter Norvig's Paradigms of AI

The following chapters will be thoroughly studied:
The following chapters will studied, if time permits.
The following chapters will not be studied:
This is a Start | Emacs | Lisp page, written Wed Nov 28 20:22:38 PST 2007.
Do you think emacs is boring to look at?
Check out this EMACS color theme tester.
If you think those screens look better than your current EMACS screen, then:
mkdir $HOME/src/lisp cd $HOME/src/lisp wget http://download.gna.org/color-theme/color-theme-6.6.0.tar.gz tar xfvz color-theme-6.6.0.tar.gz cd $HOME
Edit $HOME/.emacs with some other editor; e.g. nano .emacs.
Add these lines:
(setq load-path (cons "~/src/lisp/color-theme-6.6.0" load-path)) (require 'color-theme) (color-theme-initialize) (color-theme-hober)If it doesn't seem to work, try adding one more line:
(require 'color-theme) (setq color-theme-is-global t) (color-theme-hober)
If the hober theme don't do it for you, try some other themes:
M-x color-theme-select RET
This is a Start | Emacs | Lisp page, written Wed Nov 28 20:57:44 PST 2007.
Here's some nice tricks to add to your $HOME/.emacs
(xterm-mouse-mode t) ; make mouse work in text windows (transient-mark-mode t) ; show incremental search results (setq scroll-step 1) ; don't scroll in large jumps (setq require-final-newline t) ; every file has at least one new line (setq inhibit-startup-message t) ; disable start up screen (global-font-lock-mode t 1) ; enable syntax highlighting (line-number-mode t) ; show line numbers and time in status line ; show line numbers and time in status line (setq display-time-24hr-format nil) (display-time)
See also Color themes in EMACS.
This is a Lisp | Fun | Quotes page, written Wed Dec 5 17:30:42 PST 2007.
"...Please don't assume Lisp is only useful for Animation and Graphics, AI, Bioinformatics, B2B and E-Commerce, Data Mining, EDA/Semiconductor applications, Expert Systems, Finance, Intelligent Agents, Knowledge Management, Mechanical CAD, Modeling and Simulation, Natural Language, Optimization, Research, Risk Analysis, Scheduling, Telecom, and Web Authoring just because these are the only things they happened to list."
- Kent M. Pitman
Lisp is the red pill.
- John Fraser, comp.lang.lisp
Lisp isn't a language, it's a building material.
- Alan Kay
Lisp is a programmable programming language.
- John Foderaro, CACM, September 1991
Lisp is like a ball of mud - you can throw anything you want into it, and it's still Lisp.
- Anonymous
LISP stands for: Lots of Insane Stupid Parentheses.
- Anonymous
These are your father's parentheses. Elegant weapons, for a more... civilized age.
- XKCDp
Lisp has jokingly been called "the most intelligent way to misuse a computer". I think that description is a great compliment because it transmits the full flavor of liberation: it has assisted a number of our most gifted fellow humans in thinking previously impossible thoughts.
- "The Humble Programmer", E. Dijkstra, CACM, vol. 15, n. 10, 1972
Lisp is worth learning for 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.
- Eric S. Raymond, "How to Become a Hacker".
Any sufficiently complicated C or Fortran program contains an ad hoc informally-specified bug-ridden slow implementation of half of Common Lisp.
-Philip Greenspun's Tenth Rule of Programming
Java was, as Gosling says in the first Java white paper, designed for average programmers. It's a perfectly legitimate goal to design a language for average programmers. (Or for that matter for small children, like Logo.) But it is also a legitimate, and very different, goal to design a language for good programmers.
-Paul Graham
In Lisp, if you want to do aspect-oriented programming, you just do a bunch of macros and you're there. In Java, you have to get Gregor Kiczales to go out and start a new company, taking months and years and try to get that to work. Lisp still has the advantage there, it's just a question of people wanting that.
-Peter Norvig
Common Lisp people seem to behave in a way that is akin to the Borg: they study the various new things that people do with interest and then find that it was eminently doable in Common Lisp all along and that they can use these new techniques if they think they need them.
- Erik Naggum
This is a Ignore | Lisp page, written Wed Dec 5 15:40:31 PST 2007.
AI and advanced AI techniques. Spring 2008. LCSEE, WVU