Paradigms of Artificial Intelligence Programming (1992)
github.com
github.com
It's basically two things:
* Learn to program book written in very basic old school Common Lisp. Or, learn to program after you already know how to program. If you never really dwell deeply into code that others write to improve your own skills this is good book so start. It's programming as art or literature.
* Overview of some old AI techniques, interpreters and parsers. Old AI techniques are today's good to know heuristic algorithms.
The kerning in the PDF looks weird on my Mac, but it's really cool that this is available.
It's definitely one of my all-time-favorite programming books - my own copy is well worn by use. It's not exactly cutting edge AI in 2018, but the general programming advice is timeless and the AI samples can be seen as a fun domain to play in.
As someone mentioned, this particular scan/OCR has some wonky kerning. If you happen to be an ACM member with access to their library there's a much nicer PDF available there.
The chapters on performance tuning are timeless. Following Norvig’s thought process on how to develop computer programs is like pair programming with one of the best programmers of all time.
The quote I was looking for (found when reading the book earlier, then forgot the exact place):
"To put things in perspective, consider that Lisp is at once one of the highest-level languages available and a universal assembly language. It is a high-level language because it can easily capture data, functional, and control abstractions. It is a good assembly language because it is possible to write Lisp in a style that directly reflects the operations available on modern computers."
For an example look at https://github.com/sbcl/sbcl/blob/master/src/compiler/x86-64...
You can find similar code for other ISAs in neighbouring directories.
(DEFUN RDSYL (L DF)
(PROG (LL BRAKP ANS CH)
(SETQ DF (MERGEF DF '((* *) * *)))
AA (SETQ LL (SETQ BRAKP () ))
A (SETQ CH (OR (CAR L) #/_))
(COND ((OR (= CH #/ ) (= CH #//)) ;"/", " "
(POP L)
(SETQ CH (CAR L)))
((AND (= CH #/[) (NOT #%(ITSP))) ;"["
(SETQ BRAKP 'T))
((AND (= CH #/]) (NOT #%(ITSP))) (SETQ BRAKP () )) ;"]"
((OR (= CH #/( ) (= CH #/) )) (RETURN () )) ;Cant have parens here
((= CH #/,) ;Comma
(COND ((NOT BRAKP)
(POP L)
(GO RET))))
((= CH #/_) (GO RET)))
(PUSH CH LL)
(POP L)
(GO A)
RET (SETQ DF (MERGEF (NAMELIST (MAKNAM (NREVERSE LL))) DF))
(SETQ ANS (NCONC ANS (LIST DF)))
(AND (= CH #/,) (GO AA))
(RETURN ANS) ))
There is a lot of this kind of code around in the various Lisp Machine sources (CADR is legally available for poking around in[2]). Occasionally things like this pop up in contemporary Lisp compilers or IO/concurrency libraries. Some algorithms are much easier to express with goto.[1] https://groups.google.com/forum/#!msg/comp.lang.lisp/4nwskBo...
The CLISP implementation of Common Lisp has a virtual machine implementation.
Let's take some simple demonstration code:
[1]> (defun foo (a)
(car (cdr (if (null a)
'(1 2)
(cons 3 a)))))
FOO
Now we compile it for the CLISP virtual machine: [2]> (compile 'foo)
FOO ;
NIL ;
NIL
If we look at the disassembled virtual machine code, you'll see that the machine code has actually similar primitives for its stack machine: [3]> (disassemble 'foo)
Disassembly of function FOO
(CONST 0) = (1 2)
(CONST 1) = 3
1 required argument
0 optional arguments
No rest parameter
No keyword parameters
11 byte-code instructions:
0 (LOAD&JMPIFNOT 1 L10)
3 (CONST&PUSH 1) ; 3
4 (LOAD 2)
5 (CONS)
6 L6
6 (CDR)
7 (CAR)
8 (SKIP&RET 2)
10 L10
10 (CONST 0) ; (1 2)
11 (JMP L6)
NIL
Unrelated to that there is also the idea to program assembler code embedded in Lisp - this is often called LAP code (Lisp Assembler Program). Several implementations are using this.:+1:
But does the book dive deep enough? Won't be more useful to go with more specialized books/papers?
This misses what I found most valuable when I did get around to it. There's another thread up on HN right now, "Nobody's just reading your code". Back then I read a lot of code from books, and read more actively by treating it like a reviewer: how could this code be clearer or otherwise better, how else might you do it? Most of the time, in many other books, you wouldn't get far before seeing some clear improvement. In PAIP this basically never happened. Often enough I would think of something, but if you worked it out in detail there was some less-obvious reason the code was the way it was. At one point I spotted a bug, and he wrote back that it'd been a year since the last bug report, and he'd started to hope there weren't any more.
All the code in the book is pretty short, and it's not really "production code", but it's enough to be an education in craftsmanship at every level. I found that more interesting than the object-level topics, though they're worth learning about too.
Nowadays if you prefer Python you can get a similar experience at https://github.com/norvig/pytudes#pytudes-index-of-jupyter-i... treating different examples.
One more personal reaction I had to this book: feeling like here was someone else with some of the same values. (Only, you know, smarter.) Someone with a similar taste, who couldn't resist coming back to their code repeatedly well after it's "done". The work in the end looks pragmatic, but sort of an idealized pragmatism: you have to really want to produce your best work, to work that hard over it.
Either way, this was one of the most fun programming books I have ever read, Lisp or no Lisp.