(print *Lisp*)


Making a stand-alone executable

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 --noinform
will 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.


LISP's Local Global Trick

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


Sum, mean, median of numbers

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


How to load files faster

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 :files files2load :faslp boolean)

"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)))

The slow way: "(maker :files files2load)"

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
		  )))

Faster: "(maker :faslp t :files files2load)"

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
		  )))

And the winner is...

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)


To iterate or recurse, that is the question.

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:


Profiling code in SBCL

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."

Advice to any programmer: code it clean, profile the code, then only optimize the stuff that needs optimizing.

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.


A better way to profile SBCL code

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.

*lisp-funs*

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
))

(my-funs)

There is also a trick to find all the symbols in *package* user that are bound to a function (i.e. satisfy "fboundp") that aren't in "*lisp-funs*".
(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))

(watch code)

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)
)

Example: (watch (main))

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


LISP is different

This is a Lisp | Fun | Image page, written Thu Dec 6 10:11:34 PST 2007.



Simple LISP code

This is a Lisp | Image page, written Mon Dec 3 19:16:46 PST 2007.


LISP links

This is a Lisp page, written Mon Dec 3 19:07:15 PST 2007.

Common LISP net.

Peter Seibe's excellent text Practical Common LISP.

Lots of good material from Marty Hall.


Norvig's support code not working

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.


Good set of LISP references

This is a Lisp page, written Tue Nov 27 18:34:17 PST 2007.

Lots of good material from Marty Hall.


Getting started with LISP

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.


Getting real funky with LISP

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.


Getting started with SLIME

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).


Textbook

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:


Color themes in EMACS

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
	


Cool EMACS tricks

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.


LISP Quotes

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


Things I need to tell the students

This is a Ignore | Lisp page, written Wed Dec 5 15:40:31 PST 2007.

 

cs472 / cs572

AI and advanced AI techniques. Spring 2008. LCSEE, WVU

Venn diagram with three overlapping circles Home | News | Syllabus | Project
Lectures | LISP | EMACS | Fun
Links | Site map | Contact
NOVA
  1. Making a stand-alone executable
  2. LISP's Local Global Trick
  3. Sum, mean, median of numbers
  4. How to load files faster
  5. To iterate or recurse, that is the question.
  6. Profiling code in SBCL
  7. A better way to profile SBCL code
  8. LISP is different
  9. Simple LISP code
  10. LISP links
  11. Norvig's support code not working
  12. Good set of LISP references
  13. Getting started with LISP
  14. Getting real funky with LISP
  15. Getting started with SLIME
  16. Textbook
  17. Color themes in EMACS
  18. Cool EMACS tricks
  19. LISP Quotes
  20. Things I need to tell the students
Creative Commons License
© 2007, 2008
 Tim Menzies