forked from norvig/paip-lisp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
examples.lisp
1651 lines (1528 loc) · 68.3 KB
/
examples.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;;;; -*- Mode: Lisp; Syntax: Common-Lisp -*-
;;;; Code from Paradigms of AI Programming
;;;; Copyright (c) 1991, 1996 Peter Norvig
(requires "tutor")
(defexamples 1 "Introduction to Lisp"
"This chapter is for people with little or no experince in Lisp."
"Intermediate or advanced readers can skim or skip this chapter."
""
"Lisp expressions are in prefix notation: the operator first."
((+ 2 2) => 4 @ 4)
((+ 1 2 3 4 5 6 7 8 9 10) => 55 @ 5)
"This is Lisp for (900 + 900 + 90 + 9) - (5000 + 500 + 50 + 5)"
((- (+ 9000 900 90 9) (+ 5000 500 50 5)) => 4444)
(:section "1.1 Symbolic Computation")
"This is an example of computation on lists:"
((append '(Pat Kim) '(Robin Sandy)) => (PAT KIM ROBIN SANDY) @ 6)
"The quote mark instructs Lisp to treat the list as data."
('(pat Kim) => (PAT KIM))
"Let's look at some more list processing functions"
(:section "1.4 Lists")
((setf p '(John Q Public)) @ 10)
((first p))
((rest p))
((second p))
((third p))
((fourth p))
((length p))
"It is also possible to build up new lists"
(p @ 11)
((cons 'Mr p))
((cons (first p) (rest p)))
((setf town (list 'Anytown 'USA)))
((list p 'of town 'may 'have 'already 'won!))
((append p '(of) town '(may have already won)))
(p)
(:section "1.5 Defining New Functions")
"The special form DEFUN stands for 'define function.'"
"It is used here to define a new function called last-name:"
((requires "intro"))
((last-name p) => PUBLIC @ 13)
((last-name '(Rex Morgan MD)) => MD)
((last-name '(Spot)) => SPOT)
((last-name '(Aristotle)) => ARISTOTLE)
"We can also define the function first-name."
"Even though the definition is trivial (it is the same as FIRST),"
"it is good practice to define first-name explicitly."
(p)
((first-name p) => JOHN)
((first-name '(Wilma Flintstone)) => WILMA)
((setf names '((John Q Public) (Malcolm X)
(Admiral Grace Murray Hopper) (Spot)
(Aristotle) (A A Milne) (Z Z Top)
(Sir Larry Olivier) (Miss Scarlet))) @ 14)
((first-name (first names)) => JOHN)
(:section "1.6 Using Functions")
"Consider the following expression, which can be used to test LAST-NAME:"
((mapcar #'last-name names))
"The #' notation maps the name of a function to the function itself."
((mapcar #'- '(1 2 3 4)) @ 15)
((mapcar #'+ '(1 2 3 4) '(10 20 30 40)))
"Now that we understand mapcar, let's use it to test FIRST-NAME:"
((mapcar #'first-name names))
"Suppose we wanted a version of FIRST-NAME that ignored titles like Miss:"
((defparameter *titles*
'(Mr Mrs Miss Ms Sir Madam Dr Admiral Major General)
"A list of titles that can appear at the start of a name."))
((defun first-name (name)
"Select the first name from a name represented as a list."
(if (member (first name) *titles*)
(first-name (rest name))
(first name))) @ 16)
((mapcar #'first-name names))
((first-name '(Madam Major General Paula Jones)) => PAULA)
"We can see how this works by tracing the execution of first-name:"
((trace first-name))
((first-name '(John Q Public)) => JOHN @ 17)
((first-name '(Madam Major General Paula Jones)) => PAULA)
((untrace first-name))
(:section "1.7 Higher-Order Functions")
((apply #'+ '(1 2 3 4)) => 10)
((apply #'append '((1 2 3) (a b c))))
"Now we define a new function, self-and-double, and apply it to arguments."
((defun self-and-double (x) (list x (+ x x))))
((self-and-double 3) => (3 6))
((apply #'self-and-double '(3)) => (3 6))
"Now let's return to the mapping functions:"
((mapcar #'self-and-double '(1 10 300)))
((mappend #'self-and-double '(1 10 300)))
"FUNCALL is similar to APPLY; it too takes a function as its"
"first argument and applies the function to a list of arguments,"
"but in the case of FUNCALL, the arguments are listed separately:"
((funcall #'+ 2 3) => 5 @ 20)
((apply #'+ '(2 3)) => 5)
)
(defexamples 2 "A Simple Lisp Program"
"This chapter shows how to combine the basic functions and"
"special forms of Lisp into a complete program"
"The program generates random English sentences."
(:section "2.2 A Straightforward Solution")
"We can test the program by generating a few random sentences."
"(Note that since these are random, you won't get the same ones"
"as in the book.)"
((requires "simple"))
((sentence) @ 36)
((sentence) @ 36)
((sentence) @ 36)
((noun-phrase))
((verb-phrase))
((trace sentence noun-phrase verb-phrase article noun verb) @ 37)
((sentence))
((untrace))
(:section "2.3 A Rule-Based Solution")
"An alternative implementation concentrates on making it easy"
"to write grammar rules."
((generate 'sentence) @ 41)
((generate 'sentence) @ 41)
((generate 'noun-phrase) @ 41)
((generate 'verb-phrase) @ 41)
"One advantage of this approach is its easier to change grammars."
((setf *grammar* *bigger-grammar*) @ 43)
((generate 'sentence))
((generate 'sentence))
"Another advantage is that the same data (grammar) can be used"
"for more than one purpose. Consider generate-tree:"
((generate-tree 'sentence) @ 45))
(defexamples 3 "Overview of Lisp"
"This chapter briefly covers the most important special forms and"
"functions in Lisp."
(:section "3.2 Special Forms")
"Start with functions and special forms for repetition:"
"First, functions like MAPCAR can apply to any number of lists:"
((mapcar #'- '(1 2 3)) => (-1 -2 -3) @ 61)
((mapcar #'+ '(1 2) '(10 20) '(100 200)) => (111 222))
"Second, many of the functions accept keywords:"
((remove 1 '(1 2 3 2 1 0 -1)) => (2 3 2 0 -1) @ 61)
((remove 1 '(1 2 3 2 1 0 -1) :key #'abs) => (2 3 2 0) @ 61)
((remove 1 '(1 2 3 2 1 0 -1) :test #'<) => (1 1 0 -1) @ 61)
((remove 1 '(1 2 3 2 1 0 -1) :start 4) => (1 2 3 2 0 -1) @ 61)
"Third, some have corresponding -IF or -IF-NOT versions:"
((remove-if #'oddp '(1 2 3 2 1 0 -1)) => (2 2 0))
((remove-if-not #'oddp '(1 2 3 2 1 0 -1)) => (1 3 1 -1))
"The forms TRACE and UNTRACE are used to control debugging info:"
((requires "overview"))
((trace length9) @ 65)
((length9 '(1 b c)) => 3)
((untrace length9))
((length9 '(1 b c)) => 3)
(:section "3.7 Functions on Trees")
((setf tree '((a b) ((c)) (d e))) @ 76)
((tree-equal tree (copy-tree tree)) => t)
((same-shape-tree tree '((1 2) ((3)) (4 5))) => t)
((same-shape-tree tree '((1 2) (3) (4 5))) => nil)
"There are two functions for substituting a new expression into a tree:"
((subst 'new 'old '(old ((very old)))) => (NEW ((VERY NEW))))
((sublis '((old . new)) '(old ((very old)))) => (NEW ((VERY NEW))))
((subst 'new 'old 'old) => NEW)
"Here is an example:"
((english->french '(hello my friend - how are you today?))
=> (bonjour mon ami - comment va tu today?) @ 77)
(:section "3.10 Destructive Functions")
"Consider the following:"
((setq x '(a b c)) @ 80)
((setq y '(1 2 3)))
((nconc x y) => (a b c 1 2 3))
(x => (a b c 1 2 3))
(y => (1 2 3))
"NCONC computes the same result as APPEND, but it alters the first argument."
"It is called a 'destructive' function."
"There is quite a conceptual load on the programmer who uses NCONC."
"The advantage of NCONC is that it doesn't use any storage."
""
(:section "3.11 Overview of Data Types")
"The function TYPE-OF returns the type of its argument."
((type-of 123) => fixnum @ 82)
((typep 123 'fixnum) => t)
((typep 123 'integer) => t)
((typep 123.0 'integer) => nil)
((subtypep 'fixnum 'integer) => t)
(:section "3.12 Input/Output")
"FORMAT is the main function for formatted output:"
((format t "hello, world") @ 84)
((format t "~&~a plus ~s is ~f" "two" "two" 4))
((let ((numbers '( 1 2 3 4 5)))
(format t "~&~{~r~^ plus ~} is ~@r"
numbers (apply #'+ numbers))))
(:section "3.13 Debugging tools")
((documentation 'first 'function) @ 87)
((documentation 'pi 'variable))
(:section "3.14 Antibugging Tools")
((defun f (n) (dotimes (i n) nil)) @ 90)
((time (f 10000)))
((compile 'f))
((time (f 10000)))
(:section "3.15 Evaluation")
"The following five forms are equivalent:"
((+ 1 2 3 4) => 10 @ 91)
((funcall #'+ 1 2 3 4) => 10 @ 91)
((apply #'+ '(1 2 3 4)) => 10 @ 91)
((apply #'+ 1 2 '(3 4)) => 10 @ 91)
((eval '(+ 1 2 3 4)) => 10 @ 91)
(:section "3.16 Closures")
"In the general case, a function consists of the body of the function"
"coupled with any free lexical variables that the function references."
"Consider the example:"
((mapcar (adder 3) '(1 3 10)) => (4 6 13) @ 92)
((mapcar (adder 10) '(1 3 10)) => (11 13 20) @ 92)
"In the following, two calls to BANK-ACCOUNT create two different closures,"
"each with a separate value for the lexical variable BALANCE."
((setf my-account (bank-account 500.00)) @ 92)
((setf your-account (bank-account 250.00)) @ 93)
((funcall my-account 'withdraw 75.00) => 425.0)
((funcall your-account 'deposit 250.00) => 500.0)
((funcall your-account 'withdraw 100.00) => 400.0)
((funcall my-account 'withdraw 25.00) => 400.0)
"This style of programming is covered in more detail in chapter 13."
)
(defexamples 4 "GPS: The General Problem Solver"
"The General problem Solver, developed in 1957 by Alan Newell and Herbert"
"Simon, embodied a grandiose vision: a single computer program that could"
"solve ANY problem. GPS caused quite a stir ..."
(:section "4.4 Stage 4: test")
((requires "gps1"))
"Here are some examples of using GPS"
"The first example works with a complex chain of steps."
((gps '(son-at-home car-needs-battery have-money have-phone-book)
'(son-at-school)
*school-ops*) => SOLVED @ 118)
"The next example fails because there is no way to make the car work,"
"because we can't contact the shop to get the battery fixed."
((gps '(son-at-home car-needs-battery have-money)
'(son-at-school)
*school-ops*) => NIL)
"The third example is easy, because the car is currently working."
((gps '(son-at-home car-works)
'(son-at-school)
*school-ops*) => SOLVED)
(:section "4.7 The Clobbered Sibling Goal Problem")
"In the next example, GPS incorrectly reports success, when in fact it has"
"spent the money on the battery, and thus should fail."
((gps '(son-at-home have-money car-works)
'(have-money son-at-school)
*school-ops*) => SOLVED @ 120)
"The bug is that when (EVERY #'ACHIEVE GOALS) returns true, it means all the"
"goals were achieved in turn, but they might not still be all true."
(:section "4.8 The Leaping before You Look Problem")
"What happens if we move the HAVE-MONEY goal to the end?"
((gps '(son-at-home car-needs-battery have-money have-phone-book)
'(have-money son-at-school)
*school-ops*) => SOLVED @ 121)
"GPS returns nil, but only after executing all the actions."
"I call this the 'leaping before you look' problem, because if you asked"
"the program to solve for the two goals (JUMP-OFF-CLIFF LAND-SAFELY) it"
"would happily jump first, only to discover that it had no operator to land"
"safely. This is less than prudent behavior."
(:section "4.9 The Recursive Subgoal Problem")
"We won't show the problem (because it gets into an infinite loop),"
"but we will add the new operator to the *school-ops*; we'll use it later."
((push (make-op :action 'ask-phone-number
:preconds '(in-communication-with-shop)
:add-list '(know-phone-number))
*school-ops*) @ 122)
(:section "4.11 GPS Version 2: A More General problem Solver")
"At this point we are ready to put together a new version of GPS with"
"solutions for the 'running around the block,' 'prerequisite clobbers"
"sibling goal,' 'leaping before you look,' and 'recursive subgoal' problems."
"The most important change is that, instead of printing a message when each"
"operator is applied, we will instead have GPS return the resulting state."
((requires "gps"))
"We use the list of operators that includes the 'asking the shop their"
"phone number' operator."
((push (make-op :action 'ask-phone-number
:preconds '(in-communication-with-shop)
:add-list '(know-phone-number))
*school-ops*))
((use *school-ops*) => 7 @ 130)
"First we make sure the new version works on some of the examples that"
"version 1 worked on:"
((gps '(son-at-home car-needs-battery have-money have-phone-book)
'(son-at-school)) =>
((START)
(EXECUTING LOOK-UP-NUMBER)
(EXECUTING TELEPHONE-SHOP)
(EXECUTING TELL-SHOP-PROBLEM)
(EXECUTING GIVE-SHOP-MONEY)
(EXECUTING SHOP-INSTALLS-BATTERY)
(EXECUTING DRIVE-SON-TO-SCHOOL)) @ 131)
"We can see what is going on here by turning on debugging temporarily:"
((debug :gps))
((gps '(son-at-home car-needs-battery have-money have-phone-book)
'(son-at-school)) =>
((START)
(EXECUTING LOOK-UP-NUMBER)
(EXECUTING TELEPHONE-SHOP)
(EXECUTING TELL-SHOP-PROBLEM)
(EXECUTING GIVE-SHOP-MONEY)
(EXECUTING SHOP-INSTALLS-BATTERY)
(EXECUTING DRIVE-SON-TO-SCHOOL)) @ 131)
((undebug))
"Here is another old example:"
((gps '(son-at-home car-works)
'(son-at-school)) =>
((START)
(EXECUTING DRIVE-SON-TO-SCHOOL)) @ 132)
"Now we see that version 2 can handle the three cases version 1 got wrong."
"In each case the program avoids an infinite loop, and also avoids leaping"
"before it looks."
((gps '(son-at-home car-needs-battery have-money have-phone-book)
'(have-money son-at-school)) => NIL)
((gps '(son-at-home car-needs-battery have-money have-phone-book)
'(son-at-school have-money)) => NIL)
((gps '(son-at-home car-needs-battery have-money)
'(son-at-school)) => NIL)
"Finally, we see the new GPS also works on trivial problems:"
((gps '(son-at-home) '(son-at-home)) => ((START)))
(:section "4.12 The New Domain Problem: Monkey and Bananas")
"To show that GPS is at all general, we have to make it work in different"
"domains. We start with a 'classic' AI problem: Monkey and Bananas"
((use *banana-ops*) => 6 @ 133)
"We pose the problem of becoming not-hungry, given an initial state."
"GPS can find a solution to this problem:"
((GPS '(at-door on-floor has-ball hungry chair-at-door)
'(not-hungry)) =>
((START)
(EXECUTING PUSH-CHAIR-FROM-DOOR-TO-MIDDLE-ROOM)
(EXECUTING CLIMB-ON-CHAIR)
(EXECUTING DROP-BALL)
(EXECUTING GRASP-BANANAS)
(EXECUTING EAT-BANANAS)) @ 133)
"Notice we did not need to make any changes at all to the GPS program."
"We just used a different set of operators."
(:section "4.13 The Maze Searching Domain")
"Next we will consider another 'classic' problem, maze searching."
"We will assume a particular maze, diagrammed on page 134."
((use *maze-ops*) => 48 @ 134)
((gps '((at 1)) '((at 25))) @ 135)
"We can define FIND-PATH to use the results of a GPS search:"
((find-path 1 25) @ 136 =>
(1 2 3 4 9 8 7 12 11 16 17 22 23 24 19 20 25))
((find-path 1 1) => (1))
((equal (find-path 1 25) (reverse (find-path 25 1))) => T)
(:section "4.14 The Blocks World Domain")
"Another domain that has attracted more than its share of attention in AI"
"circles is the blocks world domain."
((use (make-block-ops '(a b))) => 4 @ 137)
"The simplest possible problem is stacking one block on another."
((gps '((a on table) (b on table) (space on a) (space on b)
(space on table))
'((a on b) (b on table))) =>
((START)
(EXECUTING (MOVE A FROM TABLE TO B))))
"Here is a slightly more complex problem: inverting a stack of two blocks."
"This time we show the debugging output:"
((debug :gps) @ 138)
((gps '((a on b) (b on table) (space on a) (space on table))
'((b on a))) =>
((START)
(EXECUTING (MOVE A FROM B TO TABLE))
(EXECUTING (MOVE B FROM TABLE TO A))))
((undebug))
"Now we move on to the three block world."
((use (make-block-ops '(a b c))) => 18)
"We try some problems:"
((gps '((a on b) (b on c) (c on table) (space on a) (space on table))
'((b on a) (c on b))) =>
((START)
(EXECUTING (MOVE A FROM B TO TABLE))
(EXECUTING (MOVE B FROM C TO A))
(EXECUTING (MOVE C FROM TABLE TO B))))
((gps '((c on a) (a on table) (b on table)
(space on c) (space on b) (space on table))
'((c on table) (a on b))) =>
((START)
(EXECUTING (MOVE C FROM A TO TABLE))
(EXECUTING (MOVE A FROM TABLE TO B))) @ 141)
((gps '((a on b) (b on c) (c on table) (space on a) (space on table))
'((b on a) (c on b))) @ 141 =>
((START)
(EXECUTING (MOVE A FROM B TO TABLE))
(EXECUTING (MOVE B FROM C TO A))
(EXECUTING (MOVE C FROM TABLE TO B))))
((gps '((a on b) (b on c) (c on table) (space on a) (space on table))
'((c on b) (b on a))) =>
((START)
(EXECUTING (MOVE A FROM B TO TABLE))
(EXECUTING (MOVE B FROM C TO A))
(EXECUTING (MOVE C FROM TABLE TO B))))
"The Sussman Anomaly"
((setf start '((c on a) (a on table) (b on table) (space on c)
(space on b) (space on table))) @ 142)
((gps start '((a on b) (b on c))) => NIL)
((gps start '((b on c) (a on b))) => NIL)
(:section "4.16 The Not Looking after You Don't Leap Problem")
((use (push (op 'taxi-son-to-school
:preconds '(son-at-home have-money)
:add-list '(son-at-school)
:del-list '(son-at-home have-money))
*school-ops*)) @ 143)
((debug :gps))
((gps '(son-at-home have-money car-works)
'(son-at-school have-money)) => NIL)
((undebug))
)
(defexamples 5 "Eliza: Dialog with a Machine"
"ELIZA was one of the first programs to feature English output as well as input."
"The program was named after the heroine of Pygmalion, who was taught to"
"speak proper English by a dedicated teacher."
(:section "5.2 Pattern Matching")
((requires "eliza1"))
"The hard part is the notion of pattern matching and transformation."
"All symbols beginning with ? are variables for the pattern matcher."
"First we see how to substitute variable/value pairs into expressions:"
((sublis '((?X . vacation)) '(what would it mean to you if you got a ?X ?))
=> (what would it mean to you if you got a VACATION ?) @ 156)
"Now a version of pat-match that works with such pairs:"
((pat-match '(I need a ?x) '(I need a vacation)) @ 158)
"Showing how to plug it in:"
((sublis (pat-match '(I need a ?x) '(I need a vacation))
'(what would it mean to you if you got a ?X ?))
=> (what would it mean to you if you got a VACATION ?) @ 159)
((pat-match '(I need a ?x) '(I really need a vacation)) => nil)
((pat-match '(this is easy) '(this is easy)) => ((t . t)))
((pat-match '(?x is ?x) '((2 + 2) is 4)) => nil)
((pat-match '(?x is ?x) '((2 + 2) is (2 + 2))) => ((?x 2 + 2)))
((pat-match '(?P need . ?X) '(I need a long vacation))
=> ((?X a long vacation) (?P . I)))
(:section "5.3 Segment Pattern Matching")
"We show how to have a variable that will match more than one element."
"We call these segment variables, and denote them (?* name)."
((pat-match '((?* ?p) need (?* ?x))
'(Mr Hulot and I need a vacation)) @ 160)
(:section "5.4 The Eliza Program: A Rule-Based Translator")
((requires "eliza"))
"We can't show you an interactive ELIZA session, because the replies are"
"random, and thus change every time. You can experiment on your own by"
"evaluating (ELIZA) and typing in your end of the conversation.
Type (good bye) when you are done."
)
(defexamples 6 "Building Software Tools"
"In chapters 4 and 5 we were concerned with buildinng two particular"
"programs, GPS and ELIZA. In this chapter, we will reexamine those"
"two programs to discover some common patterns. Those patterns will be"
"abstracted out to form reusable software tools."
(:section "6.2 A Pattern-Matching tool")
((requires "patmatch"))
((pat-match '(x = (?is ?n numberp)) '(x = 34)) => ((?n . 34)) @ 179)
((pat-match '(x = (?is ?n numberp)) '(x = x)) => NIL)
((pat-match '(?x (?or < = >) ?y) '(3 < 4)) => ((?Y . 4) (?X . 3)))
((pat-match '(x = (?and (?is ?n numberp) (?is ?n oddp))) '(x = 3))
=> ((?N . 3)))
((pat-match '(?x /= (?not ?x)) '(3 /= 4)) => ((?X . 3)) @ 180)
((pat-match '(?x > ?y (?if (> ?x ?y))) '(4 > 3)) => ((?Y . 3) (?X . 4)))
((pat-match '(a (?* ?x) d) '(a b c d)) => ((?X B C)) @ 185)
((pat-match '(a (?* ?x) (?* ?y) d) '(a b c d)) => ((?Y B C) (?X)))
((pat-match '(a (?* ?x) (?* ?y) ?x ?y) '(a b c d (b c) (d)))
=> ((?Y D) (?X B C)) @ 186)
((pat-match '(?x ?op ?y is ?z (?if (eql (funcall ?op ?x ?y) ?z)))
'(3 + 4 is 7))
=> ((?Z . 7) (?Y . 4) (?OP . +) (?X . 3)))
((pat-match '(?x ?op ?y (?if (funcall ?op ?x ?y))) '(3 > 4)) => NIL)
((pat-match-abbrev '?x* '(?* ?x)) => (?* ?X) @ 187)
((pat-match-abbrev '?y* '(?* ?y)) => (?* ?Y))
((setf axyd (expand-pat-match-abbrev '(a ?x* ?y* d)))
=> (A (?* ?X) (?* ?Y) D))
((pat-match axyd '(a b c d)) => ((?Y B C) (?X)))
((pat-match '(((?* ?x) (?* ?y)) ?x ?y) '((a b c d) (a b) (c d)))
=> NIL)
((requires "eliza-pm"))
(:section "6.4 A Set of Searching Tools")
((requires "search"))
((debug :search) @ 192)
"We can search through the binary tree, looking for, say, 12 as the goal."
"With breadth-first search this would yield an infinite loop, so we won't"
"do it. Breadth-first search works better:"
((breadth-first-search 1 (is 12) 'binary-tree) => 12 @ 193)
((depth-first-search 1 (is 12) (finite-binary-tree 15)) => 12 @ 193)
"Guiding the Search"
"Best-first search takes an additional argument which estimates how close"
"we are to the goal. We call this the cost function."
((best-first-search 1 (is 12) #'binary-tree (diff 12)) => 12 @ 195)
((best-first-search 1 (is 12) #'binary-tree (price-is-right 12)) => 12)
"The function beam-search is just like best-first-search, except that after"
"we sort the states, we then take only the first beam-width states."
((beam-search 1 (is 12) #'binary-tree (price-is-right 12) 2) => 12)
"As a concrete example of a problem that can be solved by search,"
"consider planning a flight across North America in a plane whose range is"
"limited to 1000 kilometers. Here we plan a trip from SF to Boston."
((path-state (trip (city 'san-francisco) (city 'boston)))
=> (BOSTON 71.05 42.21) @ 199)
((path-state (trip (city 'boston) (city 'san-francisco)))
=> (SAN-FRANCISCO 122.26 37.47))
((undebug :search))
((show-city-path (trip (city 'san-francisco) (city 'boston) 1)) @ 201)
((show-city-path (trip (city 'boston) (city 'san-francisco) 1)))
((show-city-path (trip (city 'boston) (city 'san-francisco) 3)) @ 202)
((iter-wide-search 1 (is 12) (finite-binary-tree 15) (diff 12)) => 12 @ 205)
((tree-search '(1) (is 6) #'next2 #'prepend) => 6 @ 208)
((graph-search '(1) (is 6) #'next2 #'prepend) => 6)
((path-states
(a*-search (list (make-path :state 1)) (is 6)
#'next2 #'(lambda (x y) 1) (diff 6))) => (6 5 3 1) @ 210)
(:section "6.5 GPS as Search")
((requires "gps-srch"))
((setf start '((c on a) (a on table) (b on table) (space on c)
(space on b) (space on table))) @ 213)
((use (make-block-ops '(a b c))) => 18)
((search-gps start '((a on b) (b on c)))
=> ((START)
(EXECUTING (MOVE C FROM A TO TABLE))
(EXECUTING (MOVE B FROM TABLE TO C))
(EXECUTING (MOVE A FROM TABLE TO B))) @ 213)
((search-gps start '((b on c) (a on b)))
=> ((START)
(EXECUTING (MOVE C FROM A TO TABLE))
(EXECUTING (MOVE B FROM TABLE TO C))
(EXECUTING (MOVE A FROM TABLE TO B))))
)
(defexamples 7 "STUDENT: Solving Algebra Word Problems"
"STUDENT was another early language understanding program, written by Daniel"
"Bobrow in 1964. It was designed to read and solve the kind of word"
"problems found in high school algebra books."
(:section "7.1 Translating English into Equations")
((requires "student"))
((translate-to-expression '(if z is 3 |,| what is twice z))
=> ((= z 3) (= what (* 2 z))) @ 222)
(:section "7.2 Solving Algebra Equations")
((trace isolate solve) @ 229)
((solve-equations '((= (+ 3 4) (* (- 5 (+ 2 x)) 7))
(= (+ (* 3 x) y) 12))) => nil)
((untrace isolate solve))
(:section "7.3 Examples")
((student '(If the number of customers Tom gets is twice the square of
20 % of the number of advertisements he runs |,|
and the number of advertisements is 45 |,|
then what is the number of customers Tom gets ?)) => nil @ 231)
((student '(The daily cost of living for a group is the overhead cost plus
the running cost for each person times the number of people in
the group |.| This cost for one group equals $ 100 |,|
and the number of people in the group is 40 |.|
If the overhead cost is 10 times the running cost |,|
find the overhead and running cost for each person |.|)))
((student '(Fran's age divided by Robin's height is one half Kelly's IQ |.|
Kelly's IQ minus 80 is Robin's height |.|
If Robin is 4 feet tall |,| how old is Fran ?)))
((student '(Fran's age divided by Robin's height is one half Kelly's IQ |.|
Kelly's IQ minus 80 is Robin's height |.|
If Robin is 0 feet tall |,| how old is Fran ?)))
)
(defexamples 8 "Symbolic Mathematics: A Simplification Program"
"'Symbolic mathematics' is to numerical mathematics as algebra is to"
"arithmetic: it deals with variables and expressions, not just numbers."
"This chapter develops a program that simplifies algebraic expressions."
"We then show that differentiation and even integration can be seen as"
"special cases of 'simplification.' (Note that we replace calls to the"
"interactive function SIMPLIFIER with calls to the function SIMP.)"
(:section "8.2 Simplification Rules")
((requires "macsymar"))
((simp '(2 + 2)) => 4 @ 245)
((simp '(5 * 20 + 30 + 7)) => 137 )
((simp '(5 * x - (4 + 1) * x)) => 0 )
((simp '(y / z * (5 * x - (4 + 1) * x))) => 0 )
((simp '((4 - 3) * x + (y / y - 1) * z)) => X )
((simp '(1 * f(x) + 0)) => (F X) )
(:section "8.3 Associativity and Commutativity")
((simp '(3 * 2 * x)) => (6 * X) @ 247)
((simp '(2 * x * x * 3)) => (6 * (X ^ 2)) )
((simp '(2 * x * 3 * y * 4 * z * 5 * 6)) => (720 * (X * (Y * Z))) )
((simp '(3 + x + 4 + x)) => ((2 * X) + 7) )
((simp '(2 * x * 3 * x * 4 * (1 / x) * 5 * 6)) => (720 * X))
(:section "8.4 Logs, Trig, and Differentiation")
((simp '(d (x + x) / d x)) => 2 @ 250)
((simp '(d (a * x ^ 2 + b * x + c) / d x)) => ((2 * (A * X)) + B) )
"For the next one, note we had an error in the first printing of the book;"
"the sign was reversed on the (d (u / v) ...) rule."
((simp '(d ((a * x ^ 2 + b * x + c) / x) / d x))
=> (((X * ((2 * (A * X)) + B)) - ((A * (X ^ 2)) + ((B * X) + C))) /
(X ^ 2)))
((simp '(log ((d (x + x) / d x) / 2))) => 0 )
((simp '(log(x + x) - log x)) => (LOG 2))
((simp '(x ^ cos pi)) => (1 / X) )
"These next two examples were also affected by the (d (u / v) ...) rule."
((simp '(d (3 * x + (cos x) / x) / d x))
=> ((((X * (- (SIN X))) - (COS X)) / (X ^ 2)) + 3))
((simp '(d ((cos x) / x) / d x))
=> (((X * (- (SIN X))) - (COS X)) / (X ^ 2)))
((simp '(d (3 * x ^ 2 + 2 * x + 1) / d x)) => ((6 * X) + 2))
((simp '(sin(x + x) ^ 2 + cos(d x ^ 2 / d x) ^ 2)) => 1 )
((simp '(sin(x + x) * sin(d x ^ 2 / d x) +
cos(2 * x) * cos(x * d 2 * y / d y))) => 1 )
(:section "8.5 Limits of Rule-Based Approaches")
"In this section we return to some examples that pose problems."
"For the following, we would prefer (2 * (x + y))"
((simp '(x + y + y + x)) => (X + (Y + (Y + X))))
"For the following, we would prefer (7 * X) and (Y + (8 * X)), respectively:"
((simp '(3 * x + 4 * x)) => ((3 * X) + (4 * X)))
((simp '(3 * x + y + x + 4 * x)) => ((3 * X) + (Y + (X + (4 * X)))) )
"In chapter 15, we develop a new version of the program that handles this problem."
(:section "8.6 Integration")
((set-simp-fn 'Int #'(lambda (exp)
(integrate (exp-lhs exp) (exp-rhs exp)))) @ 258)
((simp '(Int x * sin(x ^ 2) d x)) => (1/2 * (- (COS (X ^ 2)))) )
((simp '(Int ((3 * x ^ 3) - 1 / (3 * x ^ 3)) d x))
=> ((3 * ((X ^ 4) / 4)) - (1/3 * ((X ^ -2) / -2))) )
((simp '(Int (3 * x + 2) ^ -2/3 d x)) => (((3 * X) + 2) ^ 1/3) )
((simp '(Int sin(x) ^ 2 * cos(x) d x)) => (((SIN X) ^ 3) / 3) )
((simp '(Int sin(x) / (1 + cos(x)) d x)) => (-1 * (LOG ((COS X) + 1))) )
((simp '(Int (2 * x + 1) / (x ^ 2 + x - 1) d x))
=> (LOG ((X ^ 2) + (X - 1))) )
((simp '(Int 8 * x ^ 2 / (x ^ 3 + 2) ^ 3 d x))
=> (8 * ((1/3 * (((X ^ 3) + 2) ^ -2)) / -2)) )
((set-simp-fn 'Int
#'(lambda (exp)
(unfactorize
(factorize
(integrate (exp-lhs exp) (exp-rhs exp)))))) @ 259)
((simp '(Int 8 * x ^ 2 / (x ^ 3 + 2) ^ 3 d x))
=> (-4/3 * (((X ^ 3) + 2) ^ -2)) )
)
(defexamples 9 "Efficiency Issues"
"One of the reasons Lisp has enjoyed a long history is because it is an"
"ideal language for what is called rapid-prototyping or rapid development."
"Most real AI programs deal with large amounts of data. Thus, efficiency"
"is important. This chapter shows some ways to make programs efficient."
(:section "9.1 Caching Results of Previous Computations: Memoization")
((defun fib (n) (if (<= n 1) 1 (+ (fib (- n 1)) (fib (- n 2))))) @ 269)
((setf memo-fib (memo #'fib)) @ 270)
((trace fib))
((funcall memo-fib 3) => 3 @ 270)
((funcall memo-fib 3) => 3)
((untrace fib))
((memoize 'fib) @ 272)
((trace fib))
((fib 5) => 8)
((fib 5) => 8)
((fib 6) => 13)
((untrace fib))
)
(defexamples 10 "Low-Level Efficiency Issues"
"The efficiency techniques of the previous chapter all involved fairly"
"significant changes to an algorithm. But what happens when you are already"
"using the best imaginable algorithms, and performance is still a problem?"
(:section "10.1 Use Declarations")
"Compare these functions with and without declarations:"
((defun f (x y)
(declare (fixnum x y) (optimize (safety 0) (speed 3)))
(the fixnum (+ x y))) @ 318)
((defun g (x y) (+ x y)))
"Here is the disassembled code for f and g:"
((disassemble 'f))
((disassemble 'g) @ 319)
)
(defexamples 11 "Logic Programming"
"The idea behind logic programming is that the programmer should state the"
"relationships that describe a problem and its solution."
"In this chapter we develop an interpreter for the Prolog language."
(:section "11.1 Idea 1: A Uniform Data Base")
((requires "prolog1"))
"First let's make sure we're dealing with a brand new database."
((clear-db))
"Facts are entered into the data base with the <- macro"
((<- (likes Kim Robin)) @ 350)
((<- (likes Sandy Lee)))
((<- (likes Sandy Kim)))
((<- (likes Robin cats)))
"We can also enter rules, which state contingent facts."
((<- (likes Sandy ?x) (likes ?x cats)) @ 351)
((<- (likes Kim ?x) (likes ?x Lee) (likes ?x Kim)))
(:section "11.2 Idea 2: Unification of Logic Variables")
((requires "unify"))
((pat-match '(?x + ?y) '(2 + 1)) => ((?y . 1) (?x . 2)) @ 352)
((unify '(?x + 1) '(2 + ?y)) => ((?y . 1) (?x . 2)))
((unify '(f ?x) '(f ?y)) => ((?x . ?y)))
((unify '(?a + ?a = 0) '(?x + ?y = ?y)) => ((?y . 0) (?x . ?y) (?a . ?x)))
((unifier '(?a + ?a = 0) '(?x + ?y = ?y)) => (0 + 0 = 0))
"Let's try UNIFY on some (more) examples:"
((unify '(?x ?y a) '(?y ?x ?x)) => ((?y . a) (?x . ?y)) @ 357)
((unify '?x '(f ?x)) => nil)
((unify 'a 'a) => ((t . t)))
"Here are some examples of UNIFIER:"
((unifier '(?x ?y a) '(?y ?x ?x)) => (a a a))
((unifier '((?a * ?x ^ 2) + (?b * ?x) + ?c)
'(?z + (4 * 5) + 3))
=> ((?a * 5 ^ 2) + (4 * 5) + 3))
"Programming with Prolog"
"First we define the MEMBER relation in Prolog:"
((<- (member ?item (?item . ?rest))) @ 358)
((<- (member ?item (?x . ?rest)) (member ?item ?rest)))
"Now we can make some queries:"
((?- (member 2 (1 2 3))))
((?- (member 2 (1 2 3 2 1))))
((?- (member ?x (1 2 3))))
"Let's add one more rule to the Sandy and the cats facts:"
((<- (likes ?x ?x)) @ 363)
"Now we can ask some queries:"
((?- (likes Sandy ?who)) @ 365)
((?- (likes ?who Sandy)))
((?- (likes Robin Lee)))
((?- (likes ?x ?y) (likes ?y ?x)) @ 366)
(:section "11.3 Idea 3: Automatic Backtracking")
"Now we load the version that does automatic backtracking one step at a time"
"as opposed to the previous version, which collects all answers at once."
"Since we don't want to involve you, the user, in typing input to move on"
"to the next step, we supply the input (a ; or a .) as in the book."
"Unfortunately, it is not specified in Common Lisp whether read-char echoes"
"the character it reads, so you may or may not see the ; and . characters."
((requires "prolog"))
"Let's add the definition of the relation LENGTH:"
((<- (length () 0)) @ 370)
((<- (length (?x . ?y) (1+ ?n)) (length ?y ?n)))
"Here are some queries:"
((?- (length (a b c d) ?n)) :input ";")
((?- (length ?list (1+ (1+ 0)))) :input ";")
((?- (length ?list ?n)) :input ";;.")
((?- (length ?l (1+ (1+ 0))) (member a ?l)) :input ";;")
"(We won't try the example that leads to an infinite loop.)"
(:section "11.4 The Zebra Puzzle")
"First we define the NEXTO and IRIGHT (to the immediate right) relations:"
((<- (nextto ?x ?y ?list) (iright ?x ?y ?list)) @ 374)
((<- (nextto ?x ?y ?list) (iright ?y ?x ?list)))
((<- (iright ?left ?right (?left ?right . ?rest))))
((<- (iright ?left ?right (?x . ?rest))
(iright ?left ?right ?rest)))
((<- (= ?x ?x)))
"Now we define the zebra puzzle:"
((<- (zebra ?h ?w ?z)
;; Each house is of the form:
;; (house nationality pet cigarette drink house-color)
(= ?h ((house norwegian ? ? ? ?) ;1,10
?
(house ? ? ? milk ?) ? ?)) ; 9
(member (house englishman ? ? ? red) ?h) ; 2
(member (house spaniard dog ? ? ?) ?h) ; 3
(member (house ? ? ? coffee green) ?h) ; 4
(member (house ukrainian ? ? tea ?) ?h) ; 5
(iright (house ? ? ? ? ivory) ; 6
(house ? ? ? ? green) ?h)
(member (house ? snails winston ? ?) ?h) ; 7
(member (house ? ? kools ? yellow) ?h) ; 8
(nextto (house ? ? chesterfield ? ?) ;11
(house ? fox ? ? ?) ?h)
(nextto (house ? ? kools ? ?) ;12
(house ? horse ? ? ?) ?h)
(member (house ? ? luckystrike oj ?) ?h) ;13
(member (house japanese ? parliaments ? ?) ?h) ;14
(nextto (house norwegian ? ? ? ?) ;15
(house ? ? ? ? blue) ?h)
(member (house ?w ? ? water ?) ?h) ;Q1
(member (house ?z zebra ? ? ?) ?h))) ;Q2
"If you want to test this out, run the following query:"
" ((?- (zebra ?houses ?water-drinker ?zebra-owner)))"
"It is not included as an example because it takes a minute or so to run."
)
(defexamples 12 "Compiling Logic Programs"
"This chapter presents a compiler that translates from Prolog to Lisp."
"Unfortunatley, there's not much to see in terms of examples."
"But we load the files for you, in case you want to play with them."
((requires "prologc1" "prologc2" "prologcp"))
((prolog-compile 'likes) @ 389)
((prolog-compile 'member))
)
(defexamples 13 "Object Oriented Programming"
"It is only natural that a wide range of programming styles have been"
"introduced to attack the wide range of problems in this book."
"One style not yet covered is 'object-oriented programming'."
"Peter Wegner (1987) proposes the following formula as a definition:"
"Object-orientation = Objects + Classes + Inheritance"
(:section "13.2 Objects")
"Now we're ready to get started."
((requires "clos"))
((setf acct (new-account "J. Random Customer" 1000.00)) @ 438)
((send acct 'withdraw 500.00) => 500.0)
((send acct 'deposit 123.45) => 623.45)
((send acct 'name) => "J. Random Customer")
((send acct 'balance) => 623.45)
(:section "13.4 Classes")
"Now we define the class ACCOUNT with the define-class macro."
((define-class account (name &optional (balance 0.00))
((interest-rate .06))
(withdraw (amt) (if (<= amt balance)
(decf balance amt)
'insufficient-funds))
(deposit (amt) (incf balance amt))
(balance () balance)
(name () name)
(interest () (incf balance (* interest-rate balance)))) @ 440)
"Here are the generic functions defined by this macro:"
((setf acct2 (account "A. User" 2000.00)))
((deposit acct2 42.00) => 2042.0)
((interest acct2) => 2164.52)
((balance acct2) => 2164.52 @ 441)
((balance acct) => 623.45)
(:section "13.5 Delegation")
((define-class password-account (password acct) ()
(change-password (pass new-pass)
(if (equal pass password)
(setf password new-pass)
'wrong-password))
(otherwise (pass &rest args)
(if (equal pass password)
(apply message acct args)
'wrong-password))))
"Now we see how the class PASSWORD-ACCOUNT can be used to provide protection"
"for an existing account:"
((setf acct3 (password-account "secret" acct2)) @ 441)
((balance acct3 "secret") => 2164.52)
((withdraw acct3 "guess" 2000.00) => WRONG-PASSWORD)
((withdraw acct3 "secret" 2000.00) => 164.52)
(:section "13.7 CLOS: The Common Lisp Object System")
"Because some Lisp implementations can't convert a structure class into"
"a CLOS class, nor convert a regular function into a generic function,"
"we use the names account*, name*, balance*, interest-rate*. If you were"
"doing a real application, not just some examples, you would choose one"
"implementation and get to use the regular names."
; ?????? some problems here
((defclass account* ()
((name :initarg :name :reader name*)
(balance :initarg :balance :initform 0.00 :accessor balance*)
(interest-rate :allocation :class :initform .06
:reader interest-rate*))) @ 445)
((setf a1 (make-instance 'account* :balance 5000.00
:name "Fred")) @ 446)
((name* a1) => "Fred")
((balance* a1) => 5000.0)
((interest-rate* a1) => 0.06)
((defmethod withdraw* ((acct account*) amt)
(if (< amt (balance* acct))
(decf (balance* acct) amt)
'insufficient-funds)) @ 446)
((defclass limited-account (account*)
((limit :initarg :limit :reader limit))))
((defmethod withdraw* ((acct limited-account) amt)
(if (> amt (limit acct))
'over-limit
(call-next-method))))
((setf a2 (make-instance 'limited-account
:name "A. Thrifty Spender"
:balance 500.00 :limit 100.00)) @ 447)
((name* a2) => "A. Thrifty Spender")
((withdraw* a2 200.00) => OVER-LIMIT)
((withdraw* a2 20.00) => 480.0)
(:section "13.8 A CLOS Example: Searching Tools")
((defclass problem ()
((states :initarg :states :accessor problem-states))) @ 449)
((defmethod searcher ((prob problem))
"Find a state that solves the search problem."
(cond ((no-states-p prob) fail)
((goal-p prob) (current-state prob))
(t (let ((current (pop-state prob)))
(setf (problem-states prob)
(problem-combiner
prob
(problem-successors prob current)
(problem-states prob))))
(searcher prob)))))
((defmethod current-state ((prob problem))
"The current state is the first of the possible states."
(first (problem-states prob))))
((defmethod pop-state ((prob problem))
"Remove and return the current state."
(pop (problem-states prob))))
((defmethod no-states-p ((prob problem))
"Are there any more unexplored states?"
(null (problem-states prob))))
((defmethod searcher :before ((prob problem))
(dbg 'search "~&;; Search: ~a" (problem-states prob))) @ 450)
((defclass eql-problem (problem)
((goal :initarg :goal :reader problem-goal))))
((defmethod goal-p ((prob eql-problem))
(eql (current-state prob) (problem-goal prob))))
((defclass dfs-problem (problem) ()
(:documentation "Depth-first search problem.")))
((defclass bfs-problem (problem) ()
(:documentation "Breadth-first search problem.")))
((defmethod problem-combiner ((prob dfs-problem) new old)
"Depth-first search looks at new states first."
(append new old)))
((defmethod problem-combiner ((prob bfs-problem) new old)
"Depth-first search looks at old states first."
(append old new)))
((defclass binary-tree-problem (problem) ()) @ 451)
((defmethod problem-successors ((prob binary-tree-problem) state)
(let ((n (* 2 state)))
(list n (+ n 1)))))
((defclass binary-tree-eql-bfs-problem
(binary-tree-problem eql-problem bfs-problem) ()))
((setf p1 (make-instance 'binary-tree-eql-bfs-problem
:states '(1) :goal 12)))
((searcher p1) => 12)
((defclass best-problem (problem) ()
(:documentation "A Best-first search problem.")) @ 452)
((defmethod problem-combiner ((prob best-problem) new old)
"Best-first search sorts new and old according to cost-fn."
(sort (append new old) #'<
:key #'(lambda (state) (cost-fn prob state)))))
((defmethod cost-fn ((prob eql-problem) state)
(abs (- state (problem-goal prob)))))
((defclass beam-problem (problem)
((beam-width :initarg :beam-width :initform nil
:reader problem-beam-width))))
((defmethod problem-combiner :around ((prob beam-problem) new old)
(let ((combined (call-next-method)))
(subseq combined 0 (min (problem-beam-width prob)
(length combined))))))
((defclass binary-tree-eql-best-beam-problem
(binary-tree-problem eql-problem best-problem beam-problem)
()))
((setf p3 (make-instance 'binary-tree-eql-best-beam-problem
:states '(1) :goal 12 :beam-width 3)))
((searcher p3) => 12)
((defclass trip-problem (binary-tree-eql-best-beam-problem)
((beam-width :initform 1))) @ 453)
((defmethod cost-fn ((prob trip-problem) city)
(air-distance (problem-goal prob) city)))
((defmethod problem-successors ((prob trip-problem) city)
(neighbors city)))
((setf p4 (make-instance 'trip-problem
:states (list (city 'new-york))
:goal (city 'san-francisco))))
((searcher p4) =>
(SAN-FRANCISCO 122.26 37.47))
(:section "13.9 Is CLOS Object-oriented?")
((defmethod conc ((x null) y) y) @ 454)
((defmethod conc (x (y null)) x))
((defmethod conc ((x list) (y list))
(cons (first x) (conc (rest x) y))))
((defmethod conc ((x vector) (y vector))
(let ((vect (make-array (+ (length x) (length y)))))
(replace vect x)
(replace vect y :start1 (length x)))))