Practical Common Lisp
Practical Common Lisp
Table of Contents
1. Introduction: Why i!p"........................................................................................................................2 2. #ther, $in!e, $epe#t: % &our o' the $(P ...........................................................................................) 3. Pr#ctic#l: % Si*ple +#t#b#!e...............................................................................................................1, -. Synt#. #nd Se*#ntic!..........................................................................................................................35. /unction!..............................................................................................................................................-0 0. 1#ri#ble!...............................................................................................................................................5, 2. 3#cro!: St#nd#rd Control Con!truct!..................................................................................................21 ,. 3#cro!: +e'ining 4our 56n................................................................................................................,0 ). Pr#ctic#l: 7uilding # 8nit &e!t /r#*e6or9..........................................................................................)3 10. :u*ber!, Ch#r#cter!, #nd String!....................................................................................................103 11. Collection!........................................................................................................................................113 12. &hey C#lled It ISP 'or # $e#!on: i!t Proce!!ing..........................................................................125 13. 7eyond i!t!: 5ther 8!e! 'or Con! Cell!........................................................................................130 1-. /ile! #nd /ile I;5..............................................................................................................................1-5 15. Pr#ctic#l: % Port#ble P#thn#*e ibr#ry...........................................................................................15) 10. 5b<ect $eorient#tion: =eneric /unction!.........................................................................................102 12. 5b<ect $eorient#tion: Cl#!!e!..........................................................................................................12) 1,. % /e6 /5$3%& $ecipe!.................................................................................................................1)3 1). 7eyond (.ception >#ndling: Condition! #nd $e!t#rt!....................................................................205 20. &he Speci#l 5per#tor!......................................................................................................................215 21. Progr#**ing in the #rge: P#c9#ge! #nd Sy*bol!.........................................................................231 22. 55P 'or 7l#c9 7elt!......................................................................................................................2-3 23. Pr#ctic#l: % Sp#* /ilter...................................................................................................................250 2-. Pr#ctic#l: P#r!ing 7in#ry /ile!.........................................................................................................2225. Pr#ctic#l: %n I+3 P#r!er...................................................................................................................2)0 20. Pr#ctic#l: Web Progr#**ing 6ith %llegroSer?e.............................................................................321 22. Pr#ctic#l: %n 3P3 +#t#b#!e............................................................................................................3-1 2,. Pr#ctic#l: % Shoutc#!t Ser?er...........................................................................................................355 2). Pr#ctic#l: %n 3P3 7ro6!er..............................................................................................................3030. Pr#ctic#l: %n >&3 =ener#tion ibr#ry, the Interpreter................................................................3,2 31. Pr#ctic#l: %n >&3 =ener#tion ibr#ry, the Co*piler..................................................................3)2 32. Conclu!ion: Wh#t@! :e.t"................................................................................................................-11
So I 9ne6 t6o l#ngu#ge! in!ide #nd out #nd 6#! '#*ili#r 6ith #nother h#l' doAen. (?entu#lly, ho6e?er, I re#liAed *y intere!t in progr#**ing l#ngu#ge! 6#! re#lly rooted in the ide# pl#nted by *y '#ther@! t#le! o' i!p--th#t di''erent l#ngu#ge! re#lly #re di''erent, #nd th#t, de!pite the 'or*#l &uring eFui?#lence o' #ll progr#**ing l#ngu#ge!, you re#lly c#n get *ore done *ore Fuic9ly in !o*e l#ngu#ge! th#n other! #nd h#?e *ore 'un doing it. 4et, ironic#lly, I h#d ne?er !pent th#t *uch ti*e 6ith i!p it!el'. So, I !t#rted doing !o*e i!p h#c9ing in *y 'ree ti*e. %nd 6hene?er I did, it 6#! e.hil#r#ting ho6 Fuic9ly I 6#! #ble to go 'ro* ide# to 6or9ing code. /or e.#*ple, one ?#c#tion, h#?ing # 6ee9 or !o to h#c9 i!p, I decided to try 6riting # ?er!ion o' # progr#*--# !y!te* 'or breeding genetic #lgorith*! to pl#y the g#*e o' =o--th#t I h#d 6ritten e#rly in *y c#reer #! # D#?# progr#**er. (?en h#ndic#pped by *y then rudi*ent#ry 9no6ledge o' Co**on i!p #nd h#?ing to loo9 up e?en b#!ic 'unction!, it !till 'elt *ore producti?e th#n it 6ould h#?e been to re6rite the !#*e progr#* in D#?#, e?en 6ith !e?er#l e.tr# ye#r! o' D#?# e.perience #cFuired !ince 6riting the 'ir!t ?er!ion. % !i*il#r e.peri*ent led to the libr#ry I@ll di!cu!! in Ch#pter 2-. (#rly in *y ti*e #t Web ogic I h#d 6ritten # libr#ry, in D#?#, 'or t#9ing #p#rt D#?# cl#!! 'ile!. It 6or9ed, but the code 6#! # bit o' # *e!! #nd h#rd to *odi'y or e.tend. I h#d tried !e?er#l ti*e!, o?er the ye#r!, to re6rite th#t libr#ry, thin9ing th#t 6ith *y e?er-i*pro?ing D#?# chop! I@d 'ind !o*e 6#y to do it th#t didn@t bog do6n in pile! o' duplic#ted code. I ne?er 'ound # 6#y. 7ut 6hen I tried to do it in Co**on i!p, it too9 *e only t6o d#y!, #nd I ended up not only 6ith # D#?# cl#!! 'ile p#r!er but 6ith # gener#l-purpo!e libr#ry 'or t#9ing #p#rt #ny 9ind o' bin#ry 'ile. 4ou@ll !ee ho6 th#t libr#ry 6or9! in Ch#pter 2- #nd u!e it in Ch#pter 25 to 6rite # p#r!er 'or the I+3 t#g! e*bedded in 3P3 'ile!.
Why Lisp?
It@! h#rd, in only # 'e6 p#ge! o' #n introductory ch#pter, to e.pl#in 6hy u!er! o' # l#ngu#ge li9e it, #nd it@! e?en h#rder to *#9e the c#!e 'or 6hy you !hould in?e!t your ti*e in le#rning # cert#in l#ngu#ge. Per!on#l hi!tory only get! u! !o '#r. Perh#p! I li9e i!p bec#u!e o' !o*e Fuir9 in the 6#y *y br#in i! 6ired. It could e?en be genetic, !ince *y d#d h#! it too. So be'ore you di?e into le#rning i!p, it@! re#!on#ble to 6#nt to 9no6 6h#t the p#yo'' i! going to be. /or !o*e l#ngu#ge!, the p#yo'' i! rel#ti?ely ob?iou!. /or in!t#nce, i' you 6#nt to 6rite lo6-le?el code on 8ni., you !hould le#rn C. 5r i' you 6#nt to 6rite cert#in 9ind! o' cro!!-pl#t'or* #pplic#tion!, you !hould le#rn D#?#. %nd #ny o' # nu*ber co*p#nie! !till u!e # lot o' CEE, !o i' you 6#nt to get # <ob #t one o' the*, you !hould le#rn CEE. /or *o!t l#ngu#ge!, ho6e?er, the p#yo'' i!n@t !o e#!ily c#tegoriAedG it h#! to do 6ith !ub<ecti?e criteri# !uch #! ho6 it 'eel! to u!e the l#ngu#ge. Perl #d?oc#te! li9e to !#y th#t Perl H*#9e! e#!y thing! e#!y #nd h#rd thing! po!!ibleH #nd re?el in the '#ct th#t, #! the Perl *otto h#! it, H&here@! *ore th#n one 6#y to do it.H1 Python@! '#n!, on the other h#nd, thin9 Python i! cle#n #nd !i*ple #nd thin9 Python code i! e#!ier to under!t#nd bec#u!e, #! their *otto !#y!, H&here@! only one 6#y to do it.H So, 6hy Co**on i!p" &here@! no i**edi#tely ob?iou! p#yo'' 'or #dopting Co**on i!p the 6#y there i! 'or C, D#?#, #nd CEE Bunle!!, o' cour!e, you h#ppen to o6n # i!p 3#chineC. &he bene'it! o' u!ing i!p h#?e *uch *ore to do 6ith the e.perience o' u!ing it. I@ll !pend the re!t o' thi! boo9 !ho6ing you the !peci'ic 'e#ture! o' Co**on i!p #nd ho6 to u!e the* !o you c#n !ee 'or your!el' 6h#t it@! li9e. /or no6 I@ll try to gi?e you # !en!e o' i!p@! philo!ophy. &he ne#re!t thing Co**on i!p h#! to # *otto i! the 9o#n-li9e de!cription, Hthe progr#**#ble progr#**ing l#ngu#ge.H While cryptic, th#t de!cription get! #t the root o' the bigge!t #d?#nt#ge Co**on i!p !till h#! o?er other l#ngu#ge!. 3ore th#n #ny other l#ngu#ge, Co**on i!p 'ollo6! the
philo!ophy th#t 6h#t@! good 'or the l#ngu#ge@! de!igner i! good 'or the l#ngu#ge@! u!er!. &hu!, 6hen you@re progr#**ing in Co**on i!p, you #l*o!t ne?er 'ind your!el' 6i!hing the l#ngu#ge !upported !o*e 'e#ture th#t 6ould *#9e your progr#* e#!ier to 6rite, bec#u!e, #! you@ll !ee throughout thi! boo9, you c#n <u!t #dd the 'e#ture your!el'. Con!eFuently, # Co**on i!p progr#* tend! to pro?ide # *uch cle#rer *#pping bet6een your ide#! #bout ho6 the progr#* 6or9! #nd the code you #ctu#lly 6rite. 4our ide#! #ren@t ob!cured by boilerpl#te code #nd endle!!ly repe#ted idio*!. &hi! *#9e! your code e#!ier to *#int#in bec#u!e you don@t h#?e to 6#de through re#*! o' code e?ery ti*e you need to *#9e # ch#nge. (?en !y!te*ic ch#nge! to # progr#*@! beh#?ior c#n o'ten be #chie?ed 6ith rel#ti?ely !*#ll ch#nge! to the #ctu#l code. &hi! #l!o *e#n! you@ll de?elop code *ore Fuic9lyG there@! le!! code to 6rite, #nd you don@t 6#!te ti*e thr#!hing #round trying to 'ind # cle#n 6#y to e.pre!! your!el' 6ithin the li*it#tion! o' the l#ngu#ge.2 Co**on i!p i! #l!o #n e.cellent l#ngu#ge 'or e.plor#tory progr#**ing--i' you don@t 9no6 e.#ctly ho6 your progr#* i! going to 6or9 6hen you 'ir!t !it do6n to 6rite it, Co**on i!p pro?ide! !e?er#l 'e#ture! to help you de?elop your code incre*ent#lly #nd inter#cti?ely. /or !t#rter!, the inter#cti?e re#d-e?#l-print loop, 6hich I@ll introduce in the ne.t ch#pter, let! you continu#lly inter#ct 6ith your progr#* #! you de?elop it. Write # ne6 'unction. &e!t it. Ch#nge it. &ry # di''erent #ppro#ch. 4ou ne?er h#?e to !top 'or # lengthy co*pil#tion cycle.3 5ther 'e#ture! th#t !upport # 'lo6ing, inter#cti?e progr#**ing !tyle #re i!p@! dyn#*ic typing #nd the Co**on i!p condition !y!te*. 7ec#u!e o' the 'or*er, you !pend le!! ti*e con?incing the co*piler you !hould be #llo6ed to run your code #nd *ore ti*e #ctu#lly running it #nd 6or9ing on it,- #nd the l#tter let! you de?elop e?en your error h#ndling code inter#cti?ely. %nother con!eFuence o' being H# progr#**#ble progr#**ing l#ngu#geH i! th#t Co**on i!p, in #ddition to incorpor#ting !*#ll ch#nge! th#t *#9e p#rticul#r progr#*! e#!ier to 6rite, c#n e#!ily #dopt big ne6 ide#! #bout ho6 progr#**ing l#ngu#ge! !hould 6or9. /or in!t#nce, the origin#l i*ple*ent#tion o' the Co**on i!p 5b<ect Sy!te* BC 5SC, Co**on i!p@! po6er'ul ob<ect !y!te*, 6#! #! # libr#ry 6ritten in port#ble Co**on i!p. &hi! #llo6ed i!p progr#**er! to g#in #ctu#l e.perience 6ith the '#cilitie! it pro?ided be'ore it 6#! o''ici#lly incorpor#ted into the l#ngu#ge. Wh#te?er ne6 p#r#dig* co*e! do6n the pi9e ne.t, it@! e.tre*ely li9ely th#t Co**on i!p 6ill be #ble to #b!orb it 6ithout reFuiring #ny ch#nge! to the core l#ngu#ge. /or e.#*ple, # i!per h#! recently 6ritten # libr#ry, %!pect , th#t #dd! !upport 'or #!pect-oriented progr#**ing B%5PC to Co**on i!p.5 I' %5P turn! out to be the ne.t big thing, Co**on i!p 6ill be #ble to !upport it 6ithout #ny ch#nge! to the b#!e l#ngu#ge #nd 6ithout e.tr# preproce!!or! #nd e.tr# co*piler!.0
Where It Began
Co**on i!p i! the *odern de!cend#nt o' the i!p l#ngu#ge 'ir!t concei?ed by Dohn 3cC#rthy in 1)50. i!p circ# 1)50 6#! de!igned 'or H!y*bolic d#t# proce!!ingH2 #nd deri?ed it! n#*e 'ro* one o' the thing! it 6#! Fuite good #t: ISt Proce!!ing. We@?e co*e # long 6#y !ince then: Co**on i!p !port! #! 'ine #n #rr#y o' *odern d#t# type! #! you c#n #!9 'or: # condition !y!te* th#t, #! you@ll !ee in Ch#pter 1), pro?ide! # 6hole le?el o' 'le.ibility *i!!ing 'ro* the e.ception !y!te*! o' l#ngu#ge! !uch #! D#?#, Python, #nd CEEG po6er'ul '#cilitie! 'or doing ob<ect-oriented progr#**ingG #nd !e?er#l l#ngu#ge '#cilitie! th#t <u!t don@t e.i!t in other progr#**ing l#ngu#ge!. >o6 i! thi! po!!ible" Wh#t on (#rth 6ould pro?o9e the e?olution o' !uch # 6ell-eFuipped l#ngu#ge" Well, 3cC#rthy 6#! B#nd !till i!C #n #rti'ici#l intelligence B%IC re!e#rcher, #nd *#ny o' the 'e#ture! he built into hi! initi#l ?er!ion o' the l#ngu#ge *#de it #n e.cellent l#ngu#ge 'or %I progr#**ing. +uring
the %I boo* o' the 1),0!, i!p re*#ined # '#?orite tool 'or progr#**er! 6riting !o't6#re to !ol?e h#rd proble*! !uch #! #uto*#ted theore* pro?ing, pl#nning #nd !cheduling, #nd co*puter ?i!ion. &he!e 6ere proble*! th#t reFuired # lot o' h#rd-to-6rite !o't6#reG to *#9e # dent in the*, %I progr#**er! needed # po6er'ul l#ngu#ge, #nd they gre6 i!p into the l#ngu#ge they needed. %nd the Cold W#r helped--#! the Pent#gon poured *oney into the +e'en!e %d?#nced $e!e#rch Pro<ect! %gency B+%$P%C, # lot o' it 6ent to 'ol9! 6or9ing on proble*! !uch #! l#rge-!c#le b#ttle'ield !i*ul#tion!, #uto*#ted pl#nning, #nd n#tur#l l#ngu#ge inter'#ce!. &he!e 'ol9! #l!o u!ed i!p #nd continued pu!hing it to do 6h#t they needed. &he !#*e 'orce! th#t dro?e i!p@! 'e#ture e?olution #l!o pu!hed the en?elope #long other di*en!ion!-big %I proble*! e#t up # lot o' co*puting re!ource! ho6e?er you code the*, #nd i' you run 3oore@! l#6 in re?er!e 'or 20 ye#r!, you c#n i*#gine ho6 !c#rce co*puting re!ource! 6ere on circ#-,0! h#rd6#re. &he i!p guy! h#d to 'ind #ll 9ind! o' 6#y! to !FueeAe per'or*#nce out o' their i*ple*ent#tion!. 3odern Co**on i!p i*ple*ent#tion! #re the heir! to tho!e e#rly e''ort! #nd o'ten include Fuite !ophi!tic#ted, n#ti?e *#chine code-gener#ting co*piler!. While tod#y, th#n9! to 3oore@! l#6, it@! po!!ible to get u!#ble per'or*#nce 'ro* # purely interpreted l#ngu#ge, th#t@! no longer #n i!!ue 'or Co**on i!p. %! I@ll !ho6 in Ch#pter 32, 6ith proper Boption#lC decl#r#tion!, # good i!p co*piler c#n gener#te *#chine code Fuite !i*il#r to 6h#t *ight be gener#ted by # C co*piler. &he 1),0! 6ere #l!o the er# o' the i!p 3#chine!, 6ith !e?er#l co*p#nie!, *o!t '#*ou!ly Sy*bolic!, producing co*puter! th#t r#n i!p n#ti?ely 'ro* the chip! up. &hu!, i!p bec#*e # !y!te*! progr#**ing l#ngu#ge, u!ed 'or 6riting the oper#ting !y!te*, editor!, co*piler!, #nd pretty *uch e?erything el!e th#t r#n on the i!p 3#chine!. In '#ct, by the e#rly 1),0!, 6ith ?#riou! %I l#b! #nd the i!p *#chine ?endor! #ll pro?iding their o6n i!p i*ple*ent#tion!, there 6#! !uch # proli'er#tion o' i!p !y!te*! #nd di#lect! th#t the 'ol9! #t +%$P% beg#n to e.pre!! concern #bout the i!p co**unity !plintering. &o #ddre!! thi! concern, # gr#!!root! group o' i!p h#c9er! got together in 1),1 #nd beg#n the proce!! o' !t#nd#rdiAing # ne6 l#ngu#ge c#lled Co**on i!p th#t co*bined the be!t 'e#ture! 'ro* the e.i!ting i!p di#lect!. &heir 6or9 6#! docu*ented in the boo9 Common Lisp the Language by =uy Steele B+igit#l Pre!!, 1),-C-CLtL to the i!p-cogno!centi. 7y 1),0 the 'ir!t Co**on i!p i*ple*ent#tion! 6ere #?#il#ble, #nd the 6riting 6#! on the 6#ll 'or the di#lect! it 6#! intended to repl#ce. In 1))0, the %*eric#n :#tion#l St#nd#rd! In!titute B%:SIC rele#!ed # !t#nd#rd 'or Co**on i!p th#t built on #nd e.tended the l#ngu#ge !peci'ied in C t , #dding !o*e *#<or ne6 'e#ture! !uch #! the C 5S #nd the condition !y!te*. %nd e?en th#t 6#!n@t the l#!t 6ord: li9e C t be'ore it, the %:SI !t#nd#rd intention#lly le#?e! roo* 'or i*ple*enter! to e.peri*ent 6ith the be!t 6#y to do thing!: # 'ull i!p i*ple*ent#tion pro?ide! # rich runti*e en?iron*ent 6ith #cce!! to =8I 6idget!, *ultiple thre#d! o' control, &CP;IP !oc9et!, #nd *ore. &he!e d#y! Co**on i!p i! e?ol?ing *uch li9e other open-!ource l#ngu#ge!--the 'ol9! 6ho u!e it 6rite the libr#rie! they need #nd o'ten *#9e the* #?#il#ble to other!. In the l#!t 'e6 ye#r!, in p#rticul#r, there h#! been # !purt o' #cti?ity in open-!ource i!p libr#rie!. So, on one h#nd, i!p i! one o' co*puter !cience@! Hcl#!!ic#lH l#ngu#ge!, b#!ed on ide#! th#t h#?e !tood the te!t o' ti*e., 5n the other, it@! # thoroughly *odern, gener#l-purpo!e l#ngu#ge 6ho!e de!ign re'lect! # deeply pr#g*#tic #ppro#ch to !ol?ing re#l proble*! #! e''iciently #nd robu!tly #! po!!ible. &he only do6n!ide o' i!p@! Hcl#!!ic#lH herit#ge i! th#t lot! o' 'ol9! #re !till 6#l9ing #round 6ith ide#! #bout i!p b#!ed on !o*e p#rticul#r 'l#?or o' i!p they 6ere e.po!ed to #t !o*e p#rticul#r ti*e in the ne#rly h#l' century !ince 3cC#rthy in?ented i!p. I' !o*eone tell! you i!p i! only interpreted, th#t it@! !lo6, or th#t you h#?e to u!e recur!ion 'or e?erything, #!9 the* 6h#t di#lect o' i!p they@re t#l9ing #bout #nd 6hether people 6ere 6e#ring bell-botto*! 6hen they le#rned it.)
7ut I le#rned i!p 5nce, %nd I& W#!n@t i9e 6h#t you@re de!cribing I' you@?e u!ed i!p in the p#!t, you *#y h#?e ide#! #bout 6h#t H i!pH i! th#t h#?e little to do 6ith Co**on i!p. While Co**on i!p !uppl#nted *o!t o' the di#lect! it@! de!cended 'ro*, it i!n@t the only re*#ining i!p di#lect, #nd depending on 6here #nd 6hen you 6ere e.po!ed to i!p, you *#y ?ery 6ell h#?e le#rned one o' the!e other di#lect!. 5ther th#n Co**on i!p, the one gener#l-purpo!e i!p di#lect th#t !till h#! #n #cti?e u!er co**unity i! Sche*e. Co**on i!p borro6ed # 'e6 i*port#nt 'e#ture! 'ro* Sche*e but ne?er intended to repl#ce it. 5rigin#lly de!igned #t 3.I.&., 6here it 6#! Fuic9ly put to u!e #! # te#ching l#ngu#ge 'or undergr#du#te co*puter !cience cour!e!, Sche*e h#! #l6#y! been #i*ed #t # di''erent l#ngu#ge niche th#n Co**on i!p. In p#rticul#r, Sche*e@! de!igner! h#?e 'ocu!ed on 9eeping the core l#ngu#ge #! !*#ll #nd #! !i*ple #! po!!ible. &hi! h#! ob?iou! bene'it! 'or # te#ching l#ngu#ge #nd #l!o 'or progr#**ing l#ngu#ge re!e#rcher! 6ho li9e to be #ble to 'or*#lly pro?e thing! #bout l#ngu#ge!. It #l!o h#! the bene'it o' *#9ing it rel#ti?ely e#!y to under!t#nd the 6hole l#ngu#ge #! !peci'ied in the !t#nd#rd. 7ut, it doe! !o #t the co!t o' o*itting *#ny u!e'ul 'e#ture! th#t #re !t#nd#rdiAed in Co**on i!p. Indi?idu#l Sche*e i*ple*ent#tion! *#y pro?ide the!e 'e#ture! in i*ple*ent#tion-!peci'ic 6#y!, but their o*i!!ion 'ro* the !t#nd#rd *#9e! it h#rder to 6rite port#ble Sche*e code th#n to 6rite port#ble Co**on i!p code. Sche*e #l!o e*ph#!iAe! # 'unction#l progr#**ing !tyle #nd the u!e o' recur!ion *uch *ore th#n Co**on i!p doe!. I' you !tudied i!p in college #nd c#*e #6#y 6ith the i*pre!!ion th#t it 6#! only #n #c#de*ic l#ngu#ge 6ith no re#l-6orld #pplic#tion, ch#nce! #re you le#rned Sche*e. &hi! i!n@t to !#y th#t@! # p#rticul#rly '#ir ch#r#cteriA#tion o' Sche*e, but it@! e?en le!! #pplic#ble to Co**on i!p, 6hich 6#! e.pre!!ly de!igned to be # re#l-6orld engineering l#ngu#ge r#ther th#n # theoretic#lly HpureH l#ngu#ge. I' you@?e le#rned Sche*e, you !hould #l!o be #6#re th#t # nu*ber o' !ubtle di''erence! bet6een Sche*e #nd Co**on i!p *#y trip you up. &he!e di''erence! #re #l!o the b#!i! 'or !e?er#l perenni#l religiou! 6#r! bet6een the hothe#d! in the Co**on i!p #nd Sche*e co**unitie!. I@ll try to point out !o*e o' the *ore i*port#nt di''erence! #! 6e go #long. &6o other i!p di#lect! !till in 6ide!pre#d u!e #re (li!p, the e.ten!ion l#ngu#ge 'or the (*#c! editor, #nd %utoli!p, the e.ten!ion l#ngu#ge 'or %utode!9@! %utoC%+ co*puter-#ided de!ign tool. %lthough it@! po!!ible *ore line! o' (li!p #nd %utoli!p h#?e been 6ritten th#n o' #ny other di#lect o' i!p, neither c#n be u!ed out!ide their ho!t #pplic#tion, #nd both #re Fuite old-'#!hioned i!p! co*p#red to either Sche*e or Co**on i!p. I' you@?e u!ed one o' the!e di#lect!, prep#re to hop in the i!p ti*e *#chine #nd <u*p 'or6#rd !e?er#l dec#de!.
l#ngu#ge! you 9no6 but #re #nnoyed by !o*e i!per telling you th#t@! bec#u!e you <u!t don@t Hget it.H I' !o, thi! boo9 6ill gi?e you # !tr#ight-to-the-point introduction to Co**on i!p. I', #'ter re#ding thi! boo9, you !till thin9 Co**on i!p i! no better th#n your current '#?orite l#ngu#ge!, you@ll be in #n e.cellent po!ition to e.pl#in e.#ctly 6hy. I co?er not only the !ynt#. #nd !e*#ntic! o' the l#ngu#ge but #l!o ho6 you c#n u!e it to 6rite !o't6#re th#t doe! u!e'ul !tu''. In the 'ir!t p#rt o' the boo9, I@ll co?er the l#ngu#ge it!el', *i.ing in # 'e6 Hpr#ctic#lH ch#pter!, 6here I@ll !ho6 you ho6 to 6rite re#l code. &hen, #'ter I@?e co?ered *o!t o' the l#ngu#ge, including !e?er#l p#rt! th#t other boo9! le#?e 'or you to 'igure out on your o6n, the re*#inder o' the boo9 con!i!t! o' nine *ore pr#ctic#l ch#pter! 6here I@ll help you 6rite !e?er#l *ediu*-!iAed progr#*! th#t #ctu#lly do thing! you *ight 'ind u!e'ul: 'ilter !p#*, p#r!e bin#ry 'ile!, c#t#log 3P3!, !tre#* 3P3! o?er # net6or9, #nd pro?ide # Web inter'#ce 'or the 3P3 c#t#log #nd !er?er. %'ter you 'ini!h thi! boo9, you@ll be '#*ili#r 6ith #ll the *o!t i*port#nt 'e#ture! o' the l#ngu#ge #nd ho6 they 'it together, you@ll h#?e u!ed Co**on i!p to 6rite !e?er#l nontri?i#l progr#*!, #nd you@ll be 6ell prep#red to continue e.ploring the l#ngu#ge on your o6n. While e?eryone@! ro#d to i!p i! di''erent, I hope thi! boo9 6ill help !*ooth the 6#y 'or you. So, let@! begin.
1Perl
28n'ortun#tely,
there@! little #ctu#l re!e#rch on the producti?ity o' di''erent l#ngu#ge!. 5ne report th#t !ho6! i!p co*ing out 6ell co*p#red to CEE #nd D#?# in the co*bin#tion o' progr#**er #nd progr#* e''iciency i! di!cu!!ed #t http://www.norvig.com/java-lisp.html.
3P!ychologi!t!
h#?e identi'ied # !t#te o' *ind c#lled flow in 6hich 6e@re c#p#ble o' incredible concentr#tion #nd producti?ity. &he i*port#nce o' 'lo6 to progr#**ing h#! been recogniAed 'or ne#rly t6o dec#de! !ince it 6#! di!cu!!ed in the cl#!!ic boo9 #bout hu*#n '#ctor! in progr#**ing Peopleware: Productive Projects and Teams by &o* +e3#rco #nd &i*othy i!ter B+or!et >ou!e, 1),2C. &he t6o 9ey '#ct! #bout 'lo6 #re th#t it t#9e! #round 15 *inute! to get into # !t#te o' 'lo6 #nd th#t e?en brie' interruption! c#n bre#9 you right out o' it, reFuiring #nother 15-*inute i**er!ion to reenter. +e3#rco #nd i!ter, li9e *o!t !ub!eFuent #uthor!, concerned the*!el?e! *o!tly 6ith 'lo6de!troying interruption! !uch #! ringing telephone! #nd inopportune ?i!it! 'ro* the bo!!. e!! 'reFuently con!idered but prob#bly <u!t #! i*port#nt to progr#**er! #re the interruption! c#u!ed by our tool!. #ngu#ge! th#t reFuire, 'or in!t#nce, # lengthy co*pil#tion be'ore you c#n try your l#te!t code c#n be <u!t #! ini*ic#l to 'lo6 #! # noi!y phone or # no!y bo!!. So, one 6#y to loo9 #t i!p i! #! # l#ngu#ge de!igned to 9eep you in # !t#te o' 'lo6.
-&hi!
point i! bound to be !o*e6h#t contro?er!i#l, #t le#!t 6ith !o*e 'ol9!. St#tic ?er!u! dyn#*ic typing i! one o' the cl#!!ic religiou! 6#r! in progr#**ing. I' you@re co*ing 'ro* CEE #nd D#?# Bor 'ro* !t#tic#lly typed 'unction#l l#ngu#ge! !uch #! >#!9el #nd 3 C #nd re'u!e to con!ider li?ing 6ithout !t#tic type chec9!, you *ight #! 6ell put thi! boo9 do6n no6. >o6e?er, be'ore you do, you *ight 'ir!t 6#nt to chec9 out 6h#t !el'-de!cribed H!t#tic#lly typed bigotH $obert 3#rtin B#uthor o' Designing Object Oriented C !pplications "sing the #ooch Method JPrentice >#ll, 1))5KC #nd CEE #nd D#?# #uthor 7ruce (c9el B#uthor o' Thin$ing in C JPrentice >#ll, 1))5K #nd Thin$ing in Java JPrentice >#ll, 1)),KC h#?e h#d to !#y #bout dyn#*ic typing on their 6eblog! Bhttp://www.artima.com/weblogs/viewpost.jsp?thread=4639 #nd http://www.mindview.net/WebLog/log- !"C. 5n the other h#nd, 'ol9! co*ing 'ro* S*#llt#l9, Python, Perl, or $uby !hould 'eel right #t ho*e 6ith thi! #!pect o' Co**on i!p.
5%!pect
i! #n intere!ting pro<ect in!o'#r #! %!pectD, it! D#?#-b#!ed predece!!or, 6#! 6ritten by =regor
LicA#le!, one o' the de!igner! o' Co**on i!p@! ob<ect #nd *et#ob<ect !y!te*!. &o *#ny i!per!, %!pectD !ee*! li9e LicA#le!@! #tte*pt to b#c9port hi! ide#! 'ro* Co**on i!p into D#?#. >o6e?er, P#!c#l Co!t#nA#, the #uthor o' %!pect , thin9! there #re intere!ting ide#! in %5P th#t could be u!e'ul in Co**on i!p. 5' cour!e, the re#!on he@! #ble to i*ple*ent %!pect #! # libr#ry i! bec#u!e o' the incredible 'le.ibility o' the Co**on i!p 3et# 5b<ect Protocol LicA#le! de!igned. &o i*ple*ent %!pectD, LicA#le! h#d to 6rite 6h#t 6#! e!!enti#lly # !ep#r#te co*piler th#t co*pile! # ne6 l#ngu#ge into D#?# !ource code. &he %!pect pro<ect p#ge i! #t http://common-lisp.net/# project/aspectl/.
05r
to loo9 #t it #nother, *ore technic#lly #ccur#te, 6#y, Co**on i!p co*e! 6ith # built-in '#cility 'or integr#ting co*piler! 'or e*bedded l#ngu#ge!.
2Lisp
,Ide#!
'ir!t introduced in i!p include the i';then;el!e con!truct, recur!i?e 'unction c#ll!, dyn#*ic *e*ory #lloc#tion, g#rb#ge collection, 'ir!t-cl#!! 'unction!, le.ic#l clo!ure!, inter#cti?e progr#**ing, incre*ent#l co*pil#tion, #nd dyn#*ic typing.
)5ne
o' the *o!t co**only repe#ted *yth! #bout i!p i! th#t it@! Hde#d.H While it@! true th#t Co**on i!p i!n@t #! 6idely u!ed #!, !#y, 1i!u#l 7#!ic or D#?#, it !ee*! !tr#nge to de!cribe # l#ngu#ge th#t continue! to be u!ed 'or ne6 de?elop*ent #nd th#t continue! to #ttr#ct ne6 u!er! #! Hde#d.H So*e recent i!p !ucce!! !torie! include P#ul =r#h#*@! 1i#6eb, 6hich bec#*e 4#hoo Store 6hen 4#hoo bought hi! co*p#nyG I&% So't6#re@! #ir'#re pricing #nd !hopping !y!te*, MPN, u!ed by the online tic9et !eller 5rbitA #nd other!G :#ughty +og@! g#*e 'or the Pl#ySt#tion 2, D#9 #nd +#.ter, 6hich i! l#rgely 6ritten in # do*#in-!peci'ic i!p di#lect :#ughty +og in?ented c#lled =5% , 6ho!e co*piler i! it!el' 6ritten in Co**on i!pG #nd the $oo*b#, the #utono*ou! robotic ?#cuu* cle#ner, 6ho!e !o't6#re i! 6ritten in , # do6n6#rdly co*p#tible !ub!et o' Co**on i!p. Perh#p! e?en *ore telling i! the gro6th o' the Co**on- i!p.net Web !ite, 6hich ho!t! open-!ource Co**on i!p pro<ect!, #nd the nu*ber o' loc#l i!p u!er group! th#t h#?e !prung up in the p#!t couple o' ye#r!.
our '#?orite oper#ting !y!te*. &he 'ol9! #t /r#nA, *#9er! o' %llegro Co**on i!p, #re *#9ing #?#il#ble # tri#l ?er!ion o' their product 'or u!e 6ith thi! boo9 th#t run! on inu., Windo6!, #nd 5S N. /ol9! loo9ing 'or #n open-!ource i*ple*ent#tion h#?e !e?er#l option!. S7C - i! # high-Fu#lity open!ource i*ple*ent#tion th#t co*pile! to n#ti?e code #nd run! on # 6ide ?#riety o' 8ni.e!, including inu. #nd 5S N. S7C i! deri?ed 'ro* C38C ,5 6hich i! # Co**on i!p de?eloped #t C#rnegie 3ellon 8ni?er!ity, #nd, li9e C38C , i! l#rgely in the public do*#in, e.cept # 'e6 !ection! licen!ed under 7er9eley So't6#re +i!tribution B7S+C !tyle licen!e!. C38C it!el' i! #nother 'ine choice, though S7C tend! to be e#!ier to in!t#ll #nd no6 !upport! 21-bit 8nicode.0 /or 5S N u!er!, 5pen3C i! #n e.cellent choice--it co*pile! to *#chine code, !upport! thre#d!, #nd h#! Fuite good integr#tion 6ith 5S N@! C#rbon #nd Coco# tool9it!. 5ther open-!ource #nd co**erci#l i*ple*ent#tion! #re #?#il#ble. See Ch#pter 32 'or re!ource! 'ro* 6hich you c#n get *ore in'or*#tion. %ll the i!p code in thi! boo9 !hould 6or9 in #ny con'or*ing Co**on i!p i*ple*ent#tion unle!! other6i!e noted, #nd S I3( 6ill !*ooth out !o*e o' the di''erence! bet6een i*ple*ent#tion! by pro?iding u! 6ith # co**on inter'#ce 'or inter#cting 6ith i!p. &he output !ho6n in thi! boo9 i! 'ro* %llegro running on =:8; inu.G in !o*e c#!e!, other i!p@! *#y gener#te !lightly di''erent error *e!!#ge! or debugger output.
di''erent bu''er the current bu''er !o you c#n edit # p#rticul#r 'ile or inter#ct 6ith # p#rticul#r progr#*. &he co**#nd switch-to-b'((er, bound to the 9ey co*bin#tion $-)#b, pro*pt! 'or the n#*e o' # bu''er in the #re# #t the botto* o' the (*#c! 'r#*e. When entering # bu''er n#*e, hitting &#b 6ill co*plete the n#*e b#!ed on the ch#r#cter! typed !o '#r or 6ill !ho6 # li!t o' po!!ible co*pletion!. &he pro*pt #l!o !ugge!t! # de'#ult bu''er, 6hich you c#n #ccept <u!t by hitting $eturn. 4ou c#n #l!o !6itch bu''er! by !electing # bu''er 'ro* the 7u''er! *enu. In cert#in conte.t!, other 9ey co*bin#tion! *#y be #?#il#ble 'or !6itching to cert#in bu''er!. /or in!t#nce, 6hen editing i!p !ource 'ile!, the 9ey co*bo $-c#$-* !6itche! to the bu''er 6here you inter#ct 6ith i!p.
&hi! i! the i!p pro*pt. i9e # 8ni. or +5S !hell pro*pt, the i!p pro*pt i! # pl#ce 6here you c#n type e.pre!!ion! th#t 6ill c#u!e thing! to h#ppen. >o6e?er, in!te#d o' re#ding #nd interpreting # line o' !hell co**#nd!, i!p re#d! i!p e.pre!!ion!, e?#lu#te! the* #ccording to the rule! o' i!p, #nd print! the re!ult. &hen it doe! it #g#in 6ith the ne.t e.pre!!ion you type. &h#t endle!! cycle o' re#ding, e?#lu#ting, #nd printing i! 6hy it@! c#lled the read)eval)print loop, or $(P 'or !hort. It@! #l!o re'erred to #! the top)level, the top)level listener, or the Lisp listener. /ro* 6ithin the en?iron*ent pro?ided by the $(P , you c#n de'ine #nd rede'ine progr#* ele*ent! !uch #! ?#ri#ble!, 'unction!, cl#!!e!, #nd *ethod!G e?#lu#te #ny i!p e.pre!!ionG lo#d 'ile! cont#ining i!p !ource code or co*piled codeG co*pile 6hole 'ile! or indi?idu#l 'unction!G enter the debuggerG !tep through codeG #nd in!pect the !t#te o' indi?idu#l i!p ob<ect!. %ll tho!e '#cilitie! #re built into the l#ngu#ge, #cce!!ible ?i# 'unction! de'ined in the l#ngu#ge !t#nd#rd. I' you h#d to, you could build # pretty re#!on#ble progr#**ing en?iron*ent out o' <u!t the $(P #nd #ny te.t editor th#t 9no6! ho6 to properly indent i!p code. 7ut 'or the true i!p progr#**ing e.perience, you need #n en?iron*ent, !uch #! S I3(, th#t let! you inter#ct 6ith i!p both ?i# the $(P #nd 6hile editing !ource 'ile!. /or in!t#nce, you don@t 6#nt to h#?e to cut #nd p#!te # 'unction de'inition 'ro* # !ource 'ile to the $(P or h#?e to lo#d # 6hole 'ile <u!t bec#u!e you ch#nged one 'unctionG your i!p en?iron*ent !hould let u! e?#lu#te or co*pile both indi?idu#l e.pre!!ion! #nd 6hole 'ile! directly 'ro* your editor.
&he 'ir!t 0 i! the one you typed. &he i!p re#der, the * in $(P , re#d! the te.t H10H #nd cre#te! # i!p ob<ect repre!enting the nu*ber 10. &hi! ob<ect i! # self)evaluating ob<ect, 6hich *e#n! th#t 6hen gi?en to the e?#lu#tor, the + in $(P , it e?#lu#te! to it!el'. &hi! ?#lue i! then gi?en to the printer, 6hich print! the 0 on the line by it!el'. While th#t *#y !ee* li9e # lot o' 6or9 <u!t to get b#c9 to
6here you !t#rted, thing! get # bit *ore intere!ting 6hen you gi?e i!p !o*ething *e#tier to che6 on. /or in!t#nce, you c#n type 12#!#33 #t the i!p pro*pt.
$L-+,-./#12#!#33 "
%nything in p#renthe!e! i! # li!t, in thi! c#!e # li!t o' three ele*ent!, the !y*bol 2, #nd the nu*ber! 2 #nd 3. i!p, in gener#l, e?#lu#te! li!t! by tre#ting the 'ir!t ele*ent #! the n#*e o' # 'unction #nd the re!t o' the ele*ent! #! e.pre!!ion! to be e?#lu#ted to yield the #rgu*ent! to the 'unction. In thi! c#!e, the !y*bol 2 n#*e! # 'unction th#t per'or*! #ddition. 2 #nd 3 e?#lu#te to the*!el?e! #nd #re then p#!!ed to the #ddition 'unction, 6hich return! 5. &he ?#lue 5 i! p#!!ed to the printer, 6hich print! it. i!p c#n e?#lu#te # li!t e.pre!!ion in other 6#y!, but 6e needn@t get into the* right #6#y. /ir!t 6e h#?e to 6rite. ..
&hi! 6or9! bec#u!e !tring!, li9e nu*ber!, h#?e # liter#l !ynt#. th#t@! under!tood by the i!p re#der #nd #re !el'-e?#lu#ting ob<ect!: i!p re#d! the double-Fuoted !tring #nd in!t#nti#te! # !tring ob<ect in *e*ory th#t, 6hen e?#lu#ted, e?#lu#te! to it!el' #nd i! then printed in the !#*e liter#l !ynt#.. &he Fuot#tion *#r9! #ren@t p#rt o' the !tring ob<ect in *e*ory--they@re <u!t the !ynt#. th#t tell! the re#der to re#d # !tring. &he printer put! the* b#c9 on 6hen it print! the !tring bec#u!e it trie! to print ob<ect! in the !#*e !ynt#. the re#der under!t#nd!. >o6e?er, thi! *#y not re#lly Fu#li'y #! # Hhello, 6orldH program. It@! *ore li9e the Hhello, 6orldH value. 4ou c#n t#9e # !tep to6#rd # re#l progr#* by 6riting !o*e code th#t #! # !ide e''ect print! the !tring Hhello, 6orldH to !t#nd#rd output. Co**on i!p pro?ide! # couple 6#y! to e*it output, but the *o!t 'le.ible i! the FORMAT 'unction. FORMAT t#9e! # ?#ri#ble nu*ber o' #rgu*ent!, but the only t6o reFuired #rgu*ent! #re the pl#ce to !end the output #nd # !tring. 4ou@ll !ee in the ne.t ch#pter ho6 the !tring c#n cont#in e*bedded directi?e! th#t #llo6 you to interpol#te !ub!eFuent #rgu*ent! into the !tring, O l# print( or Python@! !tring-6. %! long #! the !tring doe!n@t cont#in #n 7, it 6ill be e*itted #!-i!. I' you p#!! t #! it! 'ir!t #rgu*ent, it !end! it! output to !t#nd#rd output. So # FORMAT e.pre!!ion th#t 6ill print Hhello, 6orldH loo9! li9e thi!:,
$L-+,-./#1(ormat#t#4hello5#world43 hello5#world 89L
5ne thing to note #bout the re!ult o' the FORMAT e.pre!!ion i! the NIL on the line #'ter the Hhello, 6orldH output. &h#t NIL i! the re!ult o' e?#lu#ting the FORMAT e.pre!!ion, printed by the $(P . BNIL i! i!p@! ?er!ion o' '#l!e #nd;or null. 3ore on th#t in Ch#pter -.C 8nli9e the other e.pre!!ion! 6e@?e !een !o '#r, # FORMAT e.pre!!ion i! *ore intere!ting 'or it! !ide e''ect--printing to !t#nd#rd output in thi! c#!e--th#n 'or it! return ?#lue. 7ut e?ery e.pre!!ion in i!p e?#lu#te! to !o*e re!ult.) >o6e?er, it@! !till #rgu#ble 6hether you@?e yet 6ritten # true Hprogr#*.H 7ut you@re getting there. %nd
you@re !eeing the botto*-up !tyle o' progr#**ing !upported by the $(P : you c#n e.peri*ent 6ith di''erent #ppro#che! #nd build # !olution 'ro* p#rt! you@?e #lre#dy te!ted. :o6 th#t you h#?e # !i*ple e.pre!!ion th#t doe! 6h#t you 6#nt, you <u!t need to p#c9#ge it in # 'unction. /unction! #re one o' the b#!ic progr#* building bloc9! in i!p #nd c#n be de'ined 6ith # DEFUN e.pre!!ion !uch #! thi!:
$L-+,-./#1de('n#hello-world#13#1(ormat#t#4hello5#world433 :-LL;-W;.L<
&he hello-world #'ter the DEFUN i! the n#*e o' the 'unction. In Ch#pter - 6e@ll loo9 #t e.#ctly 6h#t ch#r#cter! c#n be u!ed in # n#*e, but 'or no6 !u''ice it to !#y th#t lot! o' ch#r#cter!, !uch #! -, th#t #re illeg#l in n#*e! in other l#ngu#ge! #re leg#l in Co**on i!p. It@! !t#nd#rd i!p !tyle--not to *ention *ore in line 6ith nor*#l (ngli!h typogr#phy--to 'or* co*pound n#*e! 6ith hyphen!, !uch #! hello-world, r#ther th#n 6ith under!core!, #! in hello=world, or 6ith inner c#p! !uch #! helloWorld. &he 13! #'ter the n#*e deli*it the p#r#*eter li!t, 6hich i! e*pty in thi! c#!e bec#u!e the 'unction t#9e! no #rgu*ent!. &he re!t i! the body o' the 'unction. %t one le?el, thi! e.pre!!ion, li9e #ll the other! you@?e !een, i! <u!t #nother e.pre!!ion to be re#d, e?#lu#ted, #nd printed by the $(P . &he return ?#lue in thi! c#!e i! the n#*e o' the 'unction you <u!t de'ined.10 7ut li9e the FORMAT e.pre!!ion, thi! e.pre!!ion i! *ore intere!ting 'or the !ide e''ect! it h#! th#n 'or it! return ?#lue. 8nli9e the FORMAT e.pre!!ion, ho6e?er, the !ide e''ect! #re in?i!ible: 6hen thi! e.pre!!ion i! e?#lu#ted, # ne6 'unction th#t t#9e! no #rgu*ent! #nd 6ith the body 1(ormat#t# 4hello5#world43 i! cre#ted #nd gi?en the n#*e :-LL;-W;.L<. 5nce you@?e de'ined the 'unction, you c#n c#ll it li9e thi!:
$L-+,-./#1hello-world3 hello5#world 89L
4ou c#n !ee th#t the output i! <u!t the !#*e #! 6hen you e?#lu#ted the FORMAT e.pre!!ion directly, including the NIL ?#lue printed by the $(P . /unction! in Co**on i!p #uto*#tic#lly return the ?#lue o' the l#!t e.pre!!ion e?#lu#ted.
&he *e!!#ge 6ill di!#ppe#r #! you !t#rt to type e#ch ne6 ele*ent but 6ill re#ppe#r e#ch ti*e you enter # !p#ce. When you@re entering the de'inition in the 'ile, you *ight choo!e to bre#9 the de'inition #cro!!
t6o line! #'ter the p#r#*eter li!t. I' you hit $eturn #nd then &#b, S I3( 6ill #uto*#tic#lly indent the !econd line #ppropri#tely, li9e thi!:11
1de('n#hello-world#13 ##1(ormat#t#4hello5#world433
S I3( 6ill #l!o help *#tch up the p#renthe!e!--#! you type # clo!ing p#renthe!i!, it 6ill 'l#!h the corre!ponding opening p#renthe!i!. 5r you c#n <u!t type $-c#$-@ to in?o9e the co**#nd slimeclose-parens-at-point, 6hich 6ill in!ert #! *#ny clo!ing p#renthe!e! #! nece!!#ry to *#tch #ll the currently open p#renthe!e!. :o6 you c#n get thi! de'inition into your i!p en?iron*ent in !e?er#l 6#y!. &he e#!ie!t i! to type $-c# $-c 6ith the cur!or #ny6here in or i**edi#tely #'ter the DEFUN 'or*, 6hich run! the co**#nd slime-compile-de('n, 6hich in turn !end! the de'inition to i!p to be e?#lu#ted #nd co*piled. &o *#9e !ure thi! i! 6or9ing, you c#n *#9e !o*e ch#nge to hello-world, reco*pile it, #nd then go b#c9 to the $(P , u!ing $-c#$-* or $-)#b, #nd c#ll it #g#in. /or in!t#nce, you could *#9e it # bit *ore gr#**#tic#l.
1de('n#hello-world#13 ##1(ormat#t#4:ello5#worldA433
:e.t, reco*pile 6ith $-c#$-c #nd then type $-c#$-* to !6itch to the $(P to try the ne6 ?er!ion.
$L-+,-./#1hello-world3 :ello5#worldA 89L
4ou@ll #l!o prob#bly 6#nt to !#?e the 'ile you@?e been 6or9ing onG in the hello.lisp bu''er, type $)#$-s to in?o9e the (*#c! co**#nd save-b'((er. :o6 to try relo#ding thi! 'unction 'ro* the !ource 'ile, you@ll need to Fuit i!p #nd re!t#rt. &o Fuit you c#n u!e # S I3( !hortcut: #t the $(P , type # co**#. %t the botto* o' the (*#c! 6indo6, you 6ill be pro*pted 'or # co**#nd. &ype @'it Bor sa?oonaraC, #nd then hit (nter. &hi! 6ill Fuit i!p #nd clo!e #ll the bu''er! cre#ted by S I3( !uch #! the $(P bu''er.12 :o6 re!t#rt S I3( by typing %-)# slime. Du!t 'or grin!, you c#n try to in?o9e hello-world.
$L-+,-./#1hello-world3
%t th#t point S I3( 6ill pop up # ne6 bu''er th#t !t#rt! 6ith !o*ething th#t loo9! li9e thi!:
attempt#to#call#B:-LL;-W;.L<C#which#is#an#'nde(ined#('nction. ###D$ondition#o(#t?pe#+8<-E98-<-E+8$F9;8G .estarts: ## :#DF.H-IJI98G#Fr?#calling#:-LL;-W;.L<#again. ##0:#D.-F+.8-KIL+-G#.et'rn#a#val'e#instead#o(#calling#:-LL;-W;.L<. ##!:#D+,--KIL+-G#Fr?#calling#a#('nction#other#than#:-LL;-W;.L<. ##3:#D,F;.--KIL+-G#,et(#the#s?mbol-('nction#o(#:-LL;-W;.L<#and#call#it#again. ##4:#DIL;.FG#Ibort#handling#,L9%-#re@'est. ##":#DIL;.FG#Ibort#entirel?#(rom#this#process. Lac&trace: ## :#1,WI8M::<-L+J-98--%I$,#NO+8<-E98-<-E+8$F9;8#P#N)Q06b R!a/3 ##0:#11EL-F#,WI8M:,WI8M-<-L+JJ-.-:;;M#,WI8M::<-L+J-9F33
7l#**oP Wh#t h#ppened" Well, you tried to in?o9e # 'unction th#t doe!n@t e.i!t. 7ut de!pite the bur!t o' output, i!p i! #ctu#lly h#ndling thi! !itu#tion gr#ce'ully. 8nli9e D#?# or Python, Co**on i!p doe!n@t <u!t b#il--thro6ing #n e.ception #nd un6inding the !t#c9. %nd it de'initely doe!n@t du*p core <u!t bec#u!e you tried to in?o9e # *i!!ing 'unction. In!te#d i!p drop! you into the debugger. While you@re in the debugger you !till h#?e 'ull #cce!! to i!p, !o you c#n e?#lu#te e.pre!!ion! to e.#*ine the !t#te o' our progr#* #nd *#ybe e?en 'i. thing!. /or no6 don@t 6orry #bout th#tG <u!t type @ to e.it the debugger #nd get b#c9 to the $(P . &he debugger bu''er 6ill go #6#y, #nd the $(P 6ill !ho6 thi!:
$L-+,-./#1hello-world3 S#-val'ation#aborted $L-+,-./
&here@! ob?iou!ly *ore th#t c#n be done 'ro* 6ithin the debugger th#n <u!t #bort--6e@ll !ee, 'or in!t#nce, in Ch#pter 1) ho6 the debugger integr#te! 6ith the error h#ndling !y!te*. /or no6, ho6e?er, the i*port#nt thing to 9no6 i! th#t you c#n #l6#y! get out o' it, #nd b#c9 to the $(P , by typing @. 7#c9 #t the $(P you c#n try #g#in. &hing! ble6 up bec#u!e i!p didn@t 9no6 the de'inition o' hello-world. So you need to let i!p 9no6 #bout the de'inition 6e !#?ed in the 'ile hello.lisp. 4ou h#?e !e?er#l 6#y! you could do thi!. 4ou could !6itch b#c9 to the bu''er cont#ining the 'ile Btype $-)#b #nd then enter hello.lisp 6hen pro*ptedC #nd reco*pile the de'inition #! you did be'ore 6ith $-c#$-c. 5r you c#n lo#d the 6hole 'ile, 6hich 6ould be # *ore con?enient #ppro#ch i' the 'ile cont#ined # bunch o' de'inition!, u!ing the L;I< 'unction #t the $(P li9e thi!:
$L-+,-./#1load#4hello.lisp43 S#Loading#/home/peter/m?-lisp-programs/hello.lisp F
&he T *e#n! e?erything lo#ded correctly.13 o#ding # 'ile 6ith L;I< i! e!!enti#lly eFui?#lent to typing e#ch o' the e.pre!!ion! in the 'ile #t the $(P in the order they #ppe#r in the 'ile, !o #'ter the c#ll to LOAD, hello-world !hould be de'ined:
$L-+,-./#1hello-world3 :ello5#worldA 89L
%nother 6#y to lo#d # 'ile@! 6orth o' de'inition! i! to co*pile the 'ile 'ir!t 6ith COMPILE-FILE #nd then LOAD the re!ulting co*piled 'ile, c#lled # ,!-L file, 6hich i! !hort 'or fast)load file. COMPILEFILE return! the n#*e o' the /%S 'ile, !o 6e c#n co*pile #nd lo#d 'ro* the $(P li9e thi!:
$L-+,-./#1load#1compile-(ile#4hello.lisp433 SSS#$ompiling#(ile#hello.lisp SSS#Writing#(asl#(ile#hello.(asl SSS#Easl#write#complete S#East#loading#/home/peter/m?-lisp-programs/hello.(asl F
S I3( #l!o pro?ide! !upport 'or lo#ding #nd co*piling 'ile! 6ithout u!ing the $(P . When you@re in # !ource code bu''er, you c#n u!e $-c#$-l to lo#d the 'ile 6ith slime-load-(ile. (*#c! 6ill pro*pt 'or the n#*e o' # 'ile to lo#d 6ith the n#*e o' the current 'ile #lre#dy 'illed inG you c#n <u!t hit (nter. 5r you c#n type $-c#$-& to co*pile #nd lo#d the 'ile repre!ented by the current bu''er. In !o*e Co**on i!p i*ple*ent#tion!, co*piling code thi! 6#y 6ill *#9e it Fuite # bit '#!terG in other!, it 6on@t, typic#lly bec#u!e they #l6#y! co*pile e?erything. &hi! !hould be enough to gi?e you # 'l#?or o' ho6 i!p progr#**ing 6or9!. 5' cour!e I h#?en@t co?ered #ll the tric9! #nd techniFue! yet, but you@?e !een the e!!enti#l ele*ent!--inter#cting 6ith the $(P trying thing! out, lo#ding #nd te!ting ne6 code, t6e#9ing #nd debugging. Seriou! i!p h#c9er! o'ten 9eep # i!p i*#ge running 'or d#y! on end, #dding, rede'ining, #nd te!ting bit! o' their progr#* incre*ent#lly. %l!o, e?en 6hen the i!p #pp i! deployed, there@! o'ten !till # 6#y to get to # $(P . 4ou@ll !ee in Ch#pter 20 ho6 you c#n u!e the $(P #nd S I3( to inter#ct 6ith the i!p th#t@! running # Web !er?er #t the !#*e ti*e #! it@! !er?ing up Web p#ge!. It@! e?en po!!ible to u!e S I3( to connect to # i!p running on # di''erent *#chine, #llo6ing you--'or in!t#nce--to debug # re*ote !er?er <u!t li9e # loc#l one. %n e?en *ore i*pre!!i?e in!t#nce o' re*ote debugging occurred on :%S%@! 1)), +eep Sp#ce 1 *i!!ion. % h#l' ye#r #'ter the !p#ce cr#'t l#unched, # bit o' i!p code 6#! going to control the !p#cecr#'t 'or t6o d#y! 6hile conducting # !eFuence o' e.peri*ent!. 8n'ortun#tely, # !ubtle r#ce condition in the code h#d e!c#ped detection during ground te!ting #nd 6#! #lre#dy in !p#ce. When the bug *#ni'e!ted in the 6ild--100 *illion *ile! #6#y 'ro* (#rth--the te#* 6#! #ble to di#gno!e #nd 'i. the running code, #llo6ing the e.peri*ent! to co*plete.1- 5ne o' the progr#**er! de!cribed it #! 'ollo6!: +ebugging # progr#* running on # Q1003 piece o' h#rd6#re th#t i! 100 *illion *ile! #6#y i! #n intere!ting e.perience. >#?ing # re#d-e?#l-print loop running on the !p#cecr#'t pro?ed in?#lu#ble in 'inding #nd 'i.ing the proble*. 4ou@re not Fuite re#dy to !end #ny i!p code into deep !p#ce, but in the ne.t ch#pter you@ll t#9e # cr#c9 #t 6riting # progr#* # bit *ore intere!ting th#n Hhello, 6orld.H
1Superior 2I'
you@?e h#d # b#d e.perience 6ith (*#c! pre?iou!ly, you !hould tre#t i!p in # 7o. #! #n I+( th#t h#ppen! to u!e #n (*#c!-li9e editor #! it! te.t editorG there 6ill be no need to beco*e #n (*#c! guru to progr#* i!p. It i!, ho6e?er, order! o' *#gnitude *ore en<oy#ble to progr#* i!p 6ith #n editor th#t h#! !o*e b#!ic i!p #6#rene!!. %t # *ini*u*, you@ll 6#nt #n editor th#t c#n #uto*#tic#lly *#tch 13! 'or you #nd 9no6! ho6 to #uto*#tic#lly indent i!p code. 7ec#u!e (*#c! i! it!el' l#rgely 6ritten in # i!p di#lect, (li!p, it h#! Fuite # bit o' !upport 'or editing i!p code. (*#c! i! #l!o deeply e*bedded into the hi!tory o' i!p #nd the culture o' i!p h#c9er!: the origin#l (*#c! #nd it! i**edi#te predece!!or!, &(C3%CS #nd &3%CS, 6ere 6ritten by i!per! #t the 3#!!#chu!ett! In!titute o' &echnology B3I&C. &he editor! on the i!p 3#chine! 6ere ?er!ion! o' (*#c! 6ritten entirely in i!p. &he 'ir!t t6o i!p 3#chine (*#c!, 'ollo6ing the h#c9er tr#dition o' recur!i?e #crony*!, 6ere (I:( #nd RW(I, 6hich !tood 'or (I:( I! :ot (*#c! #nd RW(I W#! (I:( Initi#lly. #ter one! u!ed # de!cend#nt o' RW(I, n#*ed, *ore pro!#ic#lly, R3%CS.
3Pr#ctic#lly
!pe#9ing, there@! ?ery little li9elihood o' the l#ngu#ge !t#nd#rd it!el' being re?i!ed--6hile there #re # !*#ll h#nd'ul o' 6#rt! th#t 'ol9! *ight li9e to cle#n up, the %:SI proce!! i!n@t #*en#ble to
opening #n e.i!ting !t#nd#rd 'or *inor t6e#9!, #nd none o' the 6#rt! th#t *ight be cle#ned up #ctu#lly c#u!e #nyone #ny !eriou! di''iculty. &he 'uture o' Co**on i!p !t#nd#rdiA#tion i! li9ely to proceed ?i# de '#cto !t#nd#rd!, *uch li9e the H!t#nd#rdiA#tionH o' Perl #nd Python--#! di''erent i*ple*enter! e.peri*ent 6ith #pplic#tion progr#**ing inter'#ce! B%PI!C #nd libr#rie! 'or doing thing! not !peci'ied in the l#ngu#ge !t#nd#rd, other i*ple*enter! *#y #dopt the* or people 6ill de?elop port#bility libr#rie! to !*ooth o?er the di''erence! bet6een i*ple*ent#tion! 'or 'e#ture! not !peci'ied in the l#ngu#ge !t#nd#rd.
-Steel
5C38 0S7C
'or9ed 'ro* C38C in order to 'ocu! on cle#ning up the intern#l! #nd *#9ing it e#!ier to *#int#in. 7ut the 'or9 h#! been #*i#bleG bug 'i.e! tend to prop#g#te bet6een the t6o pro<ect!, #nd there@! t#l9 th#t !o*ed#y they 6ill *erge b#c9 together.
2&he
?ener#ble Hhello, 6orldH pred#te! e?en the cl#!!ic Lernigh#n #nd $itchie C boo9 th#t pl#yed # big role in it! popul#riA#tion. &he origin#l Hhello, 6orldH !ee*! to h#?e co*e 'ro* 7ri#n Lernigh#n@! H% &utori#l Introduction to the #ngu#ge 7H th#t 6#! p#rt o' the #ell Laboratories Computing -cience Technical *eport ./: The Programming Language # publi!hed in D#nu#ry 1)23. BIt@! #?#il#ble online #t http://cm.bell-labs.com/cm/cs/who/dmr/bintro.html.C
,&he!e )Well,
#re !o*e other e.pre!!ion! th#t #l!o print the !tring Hhello, 6orldH:
#! you@ll !ee 6hen I di!cu!! returning *ultiple ?#lue!, it@! technic#lly po!!ible to 6rite e.pre!!ion! th#t e?#lu#te to no ?#lue, but e?en !uch e.pre!!ion! #re tre#ted #! returning 89L 6hen e?#lu#ted in # conte.t th#t e.pect! # ?#lue.
10I@ll
di!cu!! in Ch#pter - 6hy the n#*e h#! been con?erted to #ll upperc#!e.
could #l!o h#?e entered the de'inition #! t6o line! #t the $(P , #! the $(P re#d! 6hole e.pre!!ion!, not line!. I3( !hortcut! #ren@t p#rt o' Co**on i!p--they@re co**#nd! to S I3(. 'or !o*e re#!on the LOAD doe!n@t go cle#nly, you@ll get #nother error #nd drop b#c9 into the debugger. I' thi! h#ppen!, the *o!t li9ely re#!on i! th#t i!p c#n@t 'ind the 'ile, prob#bly bec#u!e it! ide# o' the current 6or9ing directory i!n@t the !#*e #! 6here the 'ile i! loc#ted. In th#t c#!e, you c#n Fuit the debugger by typing @ #nd then u!e the S I3( !hortcut cd to ch#nge i!p@! ide# o' the current directory--type # co**# #nd then cd 6hen pro*pted 'or # co**#nd #nd then the n#*e o' the directory 6here hello.lisp 6#! !#?ed.
1-http://www.(lownet.com/gat/jpl-lisp.html
4ou could u!e # 'our-ite* li!t, *#pping # gi?en po!ition in the li!t to # gi?en 'ield in the record. >o6e?er, #nother 'l#?or o' li!t--c#lled # propert0 list, or plist 'or !hort--i! e?en *ore con?enient. % pli!t i! # li!t 6here e?ery other ele*ent, !t#rting 6ith the 'ir!t, i! # s0mbol th#t de!cribe! 6h#t the ne.t ele*ent in the li!t i!. I 6on@t get into #ll the det#il! o' e.#ctly 6h#t # !y*bol i! right no6G b#!ic#lly it@! # n#*e. /or the !y*bol! th#t n#*e the 'ield! in the C+ d#t#b#!e, you c#n u!e # p#rticul#r 9ind o' !y*bol, c#lled # $e0word !y*bol. % 9ey6ord i! #ny n#*e th#t !t#rt! 6ith # colon B:C, 'or in!t#nce, :(oo. >ere@! #n e.#*ple o' # pli!t u!ing the 9ey6ord !y*bol! :a, :b, #nd :c #! property n#*e!:
$L-+,-./#1list#:a#0#:b#!#:c#33 1:I#0#:L#!#:$#33
:ote th#t you c#n cre#te # property li!t 6ith the !#*e LIST 'unction #! you u!e to cre#te other li!t!G it@! the content! th#t *#9e it # pli!t. &he thing th#t *#9e! pli!t! # con?enient 6#y to repre!ent the record! in # d#t#b#!e i! the 'unction GETF, 6hich t#9e! # pli!t #nd # !y*bol #nd return! the ?#lue in the pli!t 'ollo6ing the !y*bol, *#9ing # pli!t # !ort o' poor *#n@! h#!h t#ble. i!p h#! re#l h#!h t#ble! too, but pli!t! #re !u''icient 'or your need! here #nd c#n *ore e#!ily be !#?ed to # 'ile, 6hich 6ill co*e in h#ndy l#ter.
$L-+,-./#1get(#1list#:a#0#:b#!#:c#33#:a3 0 $L-+,-./#1get(#1list#:a#0#:b#!#:c#33#:c3 3
=i?en #ll th#t, you c#n e#!ily enough 6rite # 'unction ma&e-cd th#t 6ill t#9e the 'our 'ield! #! #rgu*ent! #nd return # pli!t repre!enting th#t C+.
1de('n#ma&e-cd#1title#artist#rating#ripped3 ##1list#:title#title#:artist#artist#:rating#rating#:ripped#ripped33
&he 6ord DEFUN tell! u! th#t thi! 'or* i! de'ining # ne6 'unction. &he n#*e o' the 'unction i! ma&ecd. %'ter the n#*e co*e! the p#r#*eter li!t. &hi! 'unction h#! 'our p#r#*eter!: title, artist, rating, #nd ripped. (?erything #'ter the p#r#*eter li!t i! the body o' the 'unction. In thi! c#!e the body i! <u!t one 'or*, # c#ll to LIST. When ma&e-cd i! c#lled, the #rgu*ent! p#!!ed to the c#ll 6ill be bound to the ?#ri#ble! in the p#r#*eter li!t. /or in!t#nce, to *#9e # record 'or the C+ *oses by L#thy 3#tte#, you *ight c#ll ma&e-cd li9e thi!:
$L-+,-./#1ma&e-cd#4.oses4#4Math?#%attea4#Q#t3 1:F9FL-#4.oses4#:I.F9,F#4Math?#%attea4#:.IF98J#Q#:.9TT-<#F3#
Fi%ing #1s
% !ingle record, ho6e?er, doe! not # d#t#b#!e *#9e. 4ou need !o*e l#rger con!truct to hold the record!. %g#in, 'or !i*plicity@! !#9e, # li!t !ee*! li9e # good choice. %l!o 'or !i*plicity you c#n u!e # glob#l ?#ri#ble, UdbU, 6hich you c#n de'ine 6ith the DEFVAR *#cro. &he #!teri!9! BSC in the n#*e #re # i!p n#*ing con?ention 'or glob#l ?#ri#ble!.2
1de(var#UdbU#nil3
4ou c#n u!e the PUSH *#cro to #dd ite*! to UdbU. 7ut it@! prob#bly # good ide# to #b!tr#ct thing! # tiny bit, !o you !hould de'ine # 'unction add-record th#t #dd! # record to the d#t#b#!e.
1de('n#add-record#1cd3#1p'sh#cd#UdbU33
:o6 you c#n u!e add-record #nd ma&e-cd together to #dd C+! to the d#t#b#!e.
$L-+,-./#1add-record#1ma&e-cd#4.oses4#4Math?#%attea4#Q#t33 11:F9FL-#4.oses4#:I.F9,F#4Math?#%attea4#:.IF98J#Q#:.9TT-<#F33 $L-+,-./#1add-record#1ma&e-cd#4El?4#4<i)ie#$hic&s4#R#t33 11:F9FL-#4El?4#:I.F9,F#4<i)ie#$hic&s4#:.IF98J#R#:.9TT-<#F3 #1:F9FL-#4.oses4#:I.F9,F#4Math?#%attea4#:.IF98J#Q#:.9TT-<#F33 $L-+,-./#1add-record#1ma&e-cd#4:ome4#4<i)ie#$hic&s4#9#t33 11:F9FL-#4:ome4#:I.F9,F#4<i)ie#$hic&s4#:.IF98J#9#:.9TT-<#F3 #1:F9FL-#4El?4#:I.F9,F#4<i)ie#$hic&s4#:.IF98J#R#:.9TT-<#F3 #1:F9FL-#4.oses4#:I.F9,F#4Math?#%attea4#:.IF98J#Q#:.9TT-<#F33
&he !tu'' printed by the $(P #'ter e#ch c#ll to add-record i! the return ?#lue, 6hich i! the ?#lue returned by the l#!t e.pre!!ion in the 'unction body, the PUSH. %nd PUSH return! the ne6 ?#lue o' the ?#ri#ble it@! *odi'ying. So 6h#t you@re #ctu#lly !eeing i! the ?#lue o' the d#t#b#!e #'ter the record h#! been #dded.
>o6e?er, th#t@! not # ?ery !#ti!'ying 6#y o' loo9ing #t the output. 4ou c#n 6rite # d'mp-db 'unction th#t du*p! out the d#t#b#!e in # *ore hu*#n-re#d#ble 'or*#t, li9e thi!:
F9FL-:####:ome I.F9,F:###<i)ie#$hic&s .IF98J:###9 .9TT-<:###F F9FL-:####El? I.F9,F:###<i)ie#$hic&s .IF98J:###R .9TT-<:###F F9FL-:####.oses I.F9,F:###Math?#%attea .IF98J:###Q .9TT-<:###F
&hi! 'unction 6or9! by looping o?er #ll the ele*ent! o' UdbU 6ith the DOLIST *#cro, binding e#ch ele*ent to the ?#ri#ble cd in turn. /or e#ch ?#lue o' cd, you u!e the FORMAT 'unction to print it. %d*ittedly, the FORMAT c#ll i! # little cryptic. >o6e?er, FORMAT i!n@t p#rticul#rly *ore co*plic#ted th#n C or Perl@! print( 'unction or Python@! !tring-6 oper#tor. In Ch#pter 1, I@ll di!cu!! FORMAT in gre#ter det#il. /or no6 6e c#n t#9e thi! c#ll bit by bit. %! you !#6 in Ch#pter 2, FORMAT t#9e! #t le#!t t6o #rgu*ent!, the 'ir!t being the !tre#* 6here it !end! it! outputG t i! !horth#nd 'or the !tre#* Ustandard-o'tp'tU. &he !econd #rgu*ent to FORMAT i! # 'or*#t !tring th#t c#n cont#in both liter#l te.t #nd directi?e! telling FORMAT thing! !uch #! ho6 to interpol#te the re!t o' it! #rgu*ent!. /or*#t directi?e! !t#rt 6ith 7 B*uch the 6#y print(@! directi?e! !t#rt 6ith 6C. FORMAT under!t#nd! doAen! o' directi?e!, e#ch 6ith their o6n !et o' option!.3 >o6e?er, 'or no6 I@ll <u!t 'ocu! on the one! you need to 6rite d'mpdb. &he 7a directi?e i! the aesthetic directi?eG it *e#n! to con!u*e one #rgu*ent #nd output it in # hu*#nre#d#ble 'or*. &hi! 6ill render 9ey6ord! 6ithout the le#ding : #nd !tring! 6ithout Fuot#tion *#r9!.
/or in!t#nce:
$L-+,-./#1(ormat#t#47a4#4<i)ie#$hic&s43 <i)ie#$hic&s 89L
or:
$L-+,-./#1(ormat#t#47a4#:title3 F9FL89L
&he 7t directi?e i! 'or t#bul#ting. &he 70 t tell! FORMAT to e*it enough !p#ce! to *o?e to the tenth colu*n be'ore proce!!ing the ne.t 7a. % 7t doe!n@t con!u*e #ny #rgu*ent!.
$L-+,-./#1(ormat#t#47a:70 t7a4#:artist#4<i)ie#$hic&s43 I.F9,F:###<i)ie#$hic&s 89L
:o6 thing! get !lightly *ore co*plic#ted. When FORMAT !ee! 7V the ne.t #rgu*ent to be con!u*ed *u!t be # li!t. FORMAT loop! o?er th#t li!t, proce!!ing the directi?e! bet6een the 7V #nd 7T, con!u*ing #! *#ny ele*ent! o' the li!t #! needed e#ch ti*e through the li!t. In d'mp-db, the FORMAT loop 6ill con!u*e one 9ey6ord #nd one ?#lue 'ro* the li!t e#ch ti*e through the loop. &he 7 6 directi?e doe!n@t con!u*e #ny #rgu*ent! but tell! FORMAT to e*it # ne6line. &hen #'ter the 7T end! the loop, the l#!t 76 tell! FORMAT to e*it one *ore ne6line to put # bl#n9 line bet6een e#ch C+. &echnic#lly, you could h#?e #l!o u!ed FORMAT to loop o?er the d#t#b#!e it!el', turning our d'mp-db 'unction into # one-liner.
1de('n#d'mp-db#13 ##1(ormat#t#47V7V7a:70 t7a767W767W4#UdbU33
&h#t@! either ?ery cool or ?ery !c#ry depending on your point o' ?ie6.
4ou u!e your old 'riend FORMAT to e*it # pro*pt. :ote th#t there@! no 76 in the 'or*#t !tring, !o the cur!or 6ill !t#y on the !#*e line. &he c#ll to FORCE-OUTPUT i! nece!!#ry in !o*e i*ple*ent#tion! to en!ure th#t i!p doe!n@t 6#it 'or # ne6line be'ore it print! the pro*pt. &hen you c#n re#d # !ingle line o' te.t 6ith the #ptly n#*ed READ-LINE 'unction. &he ?#ri#ble U@'er?-ioU i! # glob#l ?#ri#ble B6hich you c#n tell bec#u!e o' the U n#*ing con?ention 'or glob#l ?#ri#ble!C th#t cont#in! the input !tre#* connected to the ter*in#l. &he return ?#lue o' prompt-read# 6ill be the ?#lue o' the l#!t 'or*, the c#ll to READ-LINE, 6hich return! the !tring it re#d B6ithout the
tr#iling ne6line.C 4ou c#n co*bine your e.i!ting ma&e-cd 'unction 6ith prompt-read to build # 'unction th#t *#9e! # ne6 C+ record 'ro* d#t# it get! by pro*pting 'or e#ch ?#lue in turn.
1de('n#prompt-(or-cd#13 ##1ma&e-cd ###1prompt-read#4Fitle43 ###1prompt-read#4Irtist43 ###1prompt-read#4.ating43 ###1prompt-read#4.ipped#D?/nG4333
&h#t@! #l*o!t right. (.cept prompt-read return! # !tring, 6hich, 6hile 'ine 'or the &itle #nd %rti!t 'ield!, i!n@t !o gre#t 'or the $#ting #nd $ipped 'ield!, 6hich !hould be # nu*ber #nd # boole#n. +epending on ho6 !ophi!tic#ted # u!er inter'#ce you 6#nt, you c#n go to #rbitr#ry length! to ?#lid#te the d#t# the u!er enter!. /or no6 let@! le#n to6#rd the Fuic9 #nd dirty: you c#n 6r#p the promptread 'or the r#ting in # c#ll to i!p@! PARSE-INTEGER 'unction, li9e thi!:
1parse-integer#1prompt-read#4.ating433
8n'ortun#tely, the de'#ult beh#?ior o' PARSE-INTEGER i! to !ign#l #n error i' it c#n@t p#r!e #n integer out o' the !tring or i' there@! #ny non-nu*eric <un9 in the !tring. >o6e?er, it t#9e! #n option#l 9ey6ord #rgu*ent :j'n&-allowed, 6hich tell! it to rel#. # bit.
1parse-integer#1prompt-read#4.ating43#:j'n&-allowed#t3
7ut there@! !till one proble*: i' it c#n@t 'ind #n integer #*id!t #ll the <un9, PARSE-INTEGER 6ill return 89L r#ther th#n # nu*ber. In 9eeping 6ith the Fuic9-#nd-dirty #ppro#ch, you *#y <u!t 6#nt to c#ll th#t 0 #nd continue. i!p@! OR *#cro i! <u!t the thing you need here. It@! !i*il#r to the H!hortcircuitingH XX in Perl, Python, D#?#, #nd CG it t#9e! # !erie! o' e.pre!!ion!, e?#lu#te! the* one #t # ti*e, #nd return! the 'ir!t non-nil ?#lue Bor NIL i' they@re #ll NILC. So you c#n u!e the 'ollo6ing:
1or#1parse-integer#1prompt-read#4.ating43#:j'n&-allowed#t3# 3
to get # de'#ult ?#lue o' 0. /i.ing the code to pro*pt 'or $ipped i! Fuite # bit !i*pler. 4ou c#n <u!t u!e the Co**on i!p 'unction Y-OR-N-P.
1?-or-n-p#4.ipped#D?/nG:#43
In '#ct, thi! 6ill be the *o!t robu!t p#rt o' prompt-(or-cd, #! Y-OR-N-P 6ill repro*pt the u!er i' they enter !o*ething th#t doe!n@t !t#rt 6ith 0, 1, n, or 2. Putting tho!e piece! together you get # re#!on#bly robu!t prompt-(or-cd 'unction.
1de('n#prompt-(or-cd#13 ##1ma&e-cd ###1prompt-read#4Fitle43 ###1prompt-read#4Irtist43 ###1or#1parse-integer#1prompt-read#4.ating43#:j'n&-allowed#t3# 3 ###1?-or-n-p#4.ipped#D?/nG:#4333
/in#lly, you c#n 'ini!h the H#dd # bunch o' C+!H inter'#ce by 6r#pping prompt-(or-cd in # 'unction th#t loop! until the u!er i! done. 4ou c#n u!e the !i*ple 'or* o' the LOOP *#cro, 6hich repe#tedly e.ecute! # body o' e.pre!!ion! until it@! e.ited by # c#ll to RETURN. /or e.#*ple:
:o6 you c#n u!e add-cds to #dd !o*e *ore C+! to the d#t#b#!e.
$L-+,-./#1add-cds3 Fitle:#.oc&inC#the#,'b'rbs Irtist:#Len#Eolds .ating:#6 .ipped##D?/nG:#? Inother?##D?/nG:#? Fitle:#Jive#+s#a#Lrea& Irtist:#Limpopo .ating:#0 .ipped##D?/nG:#? Inother?##D?/nG:#? Fitle:#L?le#Lovett Irtist:#L?le#Lovett .ating:#9 .ipped##D?/nG:#? Inother?##D?/nG:#n 89L
&he WITH-OPEN-FILE *#cro open! # 'ile, bind! the !tre#* to # ?#ri#ble, e.ecute! # !et o' e.pre!!ion!, #nd then clo!e! the 'ile. It #l!o *#9e! !ure the 'ile i! clo!ed e?en i' !o*ething goe! 6rong 6hile e?#lu#ting the body. &he li!t directly #'ter WITH-OPEN-FILE i!n@t # 'unction c#ll but r#ther p#rt o' the !ynt#. de'ined by WITH-OPEN-FILE. It cont#in! the n#*e o' the ?#ri#ble th#t 6ill hold the 'ile !tre#* to 6hich you@ll 6rite 6ithin the body o' WITH-OPEN-FILE, # ?#lue th#t *u!t be # 'ile n#*e, #nd then !o*e option! th#t control ho6 the 'ile i! opened. >ere you !peci'y th#t you@re opening the 'ile 'or 6riting 6ith :direction#:o'tp't #nd th#t you 6#nt to o?er6rite #n e.i!ting 'ile o' the !#*e n#*e i' it e.i!t! 6ith :i(-e)ists#:s'persede. 5nce you h#?e the 'ile open, #ll you h#?e to do i! print the content! o' the d#t#b#!e 6ith 1print# UdbU#o't3. 8nli9e FORMAT, PRINT print! i!p ob<ect! in # 'or* th#t c#n be re#d b#c9 in by the i!p re#der. &he *#cro WITH-STANDARD-IO-SYNTAX en!ure! th#t cert#in ?#ri#ble! th#t #''ect the beh#?ior o' PRINT #re !et to their !t#nd#rd ?#lue!. 4ou@ll u!e the !#*e *#cro 6hen you re#d the d#t# b#c9 in to *#9e !ure the i!p re#der #nd printer #re oper#ting co*p#tibly.
&he #rgu*ent to save-db !hould be # !tring cont#ining the n#*e o' the 'ile 6here the u!er 6#nt! to !#?e the d#t#b#!e. &he e.#ct 'or* o' the !tring 6ill depend on 6h#t oper#ting !y!te* they@re u!ing. /or in!t#nce, on # 8ni. bo. they !hould be #ble to c#ll save-db li9e thi!:
$L-+,-./#1save-db#47/m?-cds.db43 11:F9FL-#4L?le#Lovett4#:I.F9,F#4L?le#Lovett4#:.IF98J#9#:.9TT-<#F3 #1:F9FL-#4Jive#+s#a#Lrea&4#:I.F9,F#4Limpopo4#:.IF98J#0 #:.9TT-<#F3 #1:F9FL-#4.oc&inC#the#,'b'rbs4#:I.F9,F#4Len#Eolds4#:.IF98J#6#:.9TT-< ##F3 #1:F9FL-#4:ome4#:I.F9,F#4<i)ie#$hic&s4#:.IF98J#9#:.9TT-<#F3 #1:F9FL-#4El?4#:I.F9,F#4<i)ie#$hic&s4#:.IF98J#R#:.9TT-<#F3 #1:F9FL-#4.oses4#:I.F9,F#4Math?#%attea4#:.IF98J#9#:.9TT-<#F33
5n Windo6!, the 'ilen#*e *ight be !o*ething li9e Hc:/m?-cds.dbH or Hc:YYm?-cds.db.H4ou c#n open thi! 'ile in #ny te.t editor to !ee 6h#t it loo9! li9e. 4ou !hould !ee !o*ething # lot li9e 6h#t the $(P print! i' you type UdbU. &he 'unction to lo#d the d#t#b#!e b#c9 in i! !i*il#r.
1de('n#load-db#1(ilename3 ##1with-open-(ile#1in#(ilename3 ####1with-standard-io-s?nta) ######1set(#UdbU#1read#in33333
&hi! ti*e you don@t need to !peci'y :direction in the option! to WITH-OPEN-FILE, !ince you 6#nt the de'#ult o' :inp't. %nd in!te#d o' printing, you u!e the 'unction READ to re#d 'ro* the !tre#* in. &hi! i! the !#*e re#der u!ed by the $(P #nd c#n re#d #ny i!p e.pre!!ion you could type #t the $(P pro*pt. >o6e?er, in thi! c#!e, you@re <u!t re#ding #nd !#?ing the e.pre!!ion, not e?#lu#ting it. %g#in, the WITH-STANDARD-IO-SYNTAX *#cro en!ure! th#t READ i! u!ing the !#*e b#!ic !ynt#. th#t save-db did 6hen it PRINTed the d#t#. &he SETF *#cro i! Co**on i!p@! *#in #!!ign*ent oper#tor. It !et! it! 'ir!t #rgu*ent to the re!ult o' e?#lu#ting it! !econd #rgu*ent. So in load-db the UdbU ?#ri#ble 6ill cont#in the ob<ect re#d 'ro* the 'ile, n#*ely, the li!t o' li!t! 6ritten by save-db. 4ou do need to be c#re'ul #bout one thing-load-db clobber! 6h#te?er 6#! in UdbU be'ore the c#ll. So i' you@?e #dded record! 6ith addrecord or add-cds th#t h#?en@t been !#?ed 6ith save-db, you@ll lo!e the*.
#nd get # li!t o' #ll the record! 6here the #rti!t i! the +i.ie Chic9!. %g#in, it turn! out th#t the choice o' !#?ing the record! in # li!t 6ill p#y o''. &he 'unction REMOVE-IF-NOT t#9e! # predic#te #nd # li!t #nd return! # li!t cont#ining only the ele*ent! o' the origin#l li!t th#t *#tch the predic#te. In other 6ord!, it h#! re*o?ed #ll the ele*ent! th#t don@t *#tch the predic#te. >o6e?er, REMOVE-IF-NOT doe!n@t re#lly re*o?e #nything--it cre#te! # ne6 li!t, le#?ing the origin#l li!t untouched. It@! li9e running grep o?er # 'ile. &he predic#te #rgu*ent
c#n be #ny 'unction th#t #ccept! # !ingle #rgu*ent #nd return! # boole#n ?#lue--NIL 'or '#l!e #nd #nything el!e 'or true. /or in!t#nce, i' you 6#nted to e.tr#ct #ll the e?en ele*ent! 'ro* # li!t o' nu*ber!, you could u!e REMOVE-IF-NOT #! 'ollo6!:
$L-+,-./#1remove-i(-not#NCevenp#C10#!#3#4#"#6#Q#R#9#0 33 1!#4#6#R#0 3
In thi! c#!e, the predic#te i! the 'unction EVENP, 6hich return! true i' it! #rgu*ent i! #n e?en nu*ber. &he 'unny not#tion NC i! !horth#nd 'or H=et *e the 'unction 6ith the 'ollo6ing n#*e.H Without the NC, i!p 6ould tre#t evenp #! the n#*e o' # ?#ri#ble #nd loo9 up the ?#lue o' the ?#ri#ble, not the 'unction. 4ou c#n #l!o p#!! REMOVE-IF-NOT #n #nony*ou! 'unction. /or in!t#nce, i' EVENP didn@t e.i!t, you could 6rite the pre?iou! e.pre!!ion #! the 'ollo6ing:
$L-+,-./#1remove-i(-not#NC1lambda#1)3#1=# #1mod#)#!333#C10#!#3#4#"#6#Q#R#9#0 33 1!#4#6#R#0 3
6hich chec9! th#t it! #rgu*ent i! eFu#l to 0 *odulu! 2 Bin other 6ord!, i! e?enC. I' you 6#nted to e.tr#ct only the odd nu*ber! u!ing #n #nony*ou! 'unction, you@d 6rite thi!:
$L-+,-./#1remove-i(-not#NC1lambda#1)3#1=#0#1mod#)#!333#C10#!#3#4#"#6#Q#R#9#0 33 10#3#"#Q#93
:ote th#t lambda i!n@t the n#*e o' the 'unction--it@! the indic#tor you@re de'ining #n #nony*ou! 'unction.5 5ther th#n the l#c9 o' # n#*e, ho6e?er, # LAMBDA e.pre!!ion loo9! # lot li9e # DEFUN: the 6ord lambda i! 'ollo6ed by # p#r#*eter li!t, 6hich i! 'ollo6ed by the body o' the 'unction. &o !elect #ll the +i.ie Chic9!@ #lbu*! in the d#t#b#!e u!ing REMOVE-IF-NOT, you need # 'unction th#t return! true 6hen the #rti!t 'ield o' # record i! 4<i)ie#$hic&s4. $e*e*ber th#t 6e cho!e the pli!t repre!ent#tion 'or the d#t#b#!e record! bec#u!e the 'unction GETF c#n e.tr#ct n#*ed 'ield! 'ro* # pli!t. So #!!u*ing cd i! the n#*e o' # ?#ri#ble holding # !ingle d#t#b#!e record, you c#n u!e the e.pre!!ion 1get(#cd#:artist3 to e.tr#ct the n#*e o' the #rti!t. &he 'unction EQUAL, 6hen gi?en !tring #rgu*ent!, co*p#re! the* ch#r#cter by ch#r#cter. So 1e@'al#1get(#cd#:artist3# 4<i)ie#$hic&s43 6ill te!t 6hether the #rti!t 'ield o' # gi?en C+ i! eFu#l to 4<i)ie#$hic&s4. %ll you need to do i! 6r#p th#t e.pre!!ion in # LAMBDA 'or* to *#9e #n #nony*ou! 'unction #nd p#!! it to REMOVE-IF-NOT.
$L-+,-./#1remove-i(-not ##NC1lambda#1cd3#1e@'al#1get(#cd#:artist3#4<i)ie#$hic&s433#UdbU3 11:F9FL-#4:ome4#:I.F9,F#4<i)ie#$hic&s4#:.IF98J#9#:.9TT-<#F3 #1:F9FL-#4El?4#:I.F9,F#4<i)ie#$hic&s4#:.IF98J#R#:.9TT-<#F33
:o6 !uppo!e you 6#nt to 6r#p th#t 6hole e.pre!!ion in # 'unction th#t t#9e! the n#*e o' the #rti!t #! #n #rgu*ent. 4ou c#n 6rite th#t li9e thi!:
1de('n#select-b?-artist#1artist3 ##1remove-i(-not ###NC1lambda#1cd3#1e@'al#1get(#cd#:artist3#artist33 ###UdbU33
:ote ho6 the #nony*ou! 'unction, 6hich cont#in! code th#t 6on@t run until it@! in?o9ed in REMOVEIF-NOT, c#n nonethele!! re'er to the ?#ri#ble artist. In thi! c#!e the #nony*ou! 'unction doe!n@t <u!t !#?e you 'ro* h#?ing to 6rite # regul#r 'unction--it let! you 6rite # 'unction th#t deri?e! p#rt o' it! *e#ning--the ?#lue o' artist--'ro* the conte.t in 6hich it@! e*bedded. So th#t@! select-b?-artist. >o6e?er, !electing by #rti!t i! only one o' the 9ind! o' Fuerie! you *ight li9e to !upport. 4ou could 6rite !e?er#l *ore 'unction!, !uch #! select-b?-title, select-b?-rating, select-b?-title-and-artist, #nd !o on. 7ut they@d #ll be #bout the !#*e e.cept 'or the content! o' the #nony*ou! 'unction. 4ou c#n in!te#d *#9e # *ore gener#l select 'unction th#t t#9e! # 'unction #! #n #rgu*ent.
1de('n#select#1selector-(n3 ##1remove-i(-not#selector-(n#UdbU33
So 6h#t h#ppened to the NC" Well, in thi! c#!e you don@t 6#nt REMOVE-IF-NOT to u!e the 'unction n#*ed selector-(n. 4ou 6#nt it to u!e the #nony*ou! 'unction th#t 6#! p#!!ed #! #n #rgu*ent to select in the variable selector-(n. &hough, the NC co*e! b#c9 in the call to select.
$L-+,-./#1select#NC1lambda#1cd3#1e@'al#1get(#cd#:artist3#4<i)ie#$hic&s4333 11:F9FL-#4:ome4#:I.F9,F#4<i)ie#$hic&s4#:.IF98J#9#:.9TT-<#F3 #1:F9FL-#4El?4#:I.F9,F#4<i)ie#$hic&s4#:.IF98J#R#:.9TT-<#F33
7ut th#t@! re#lly Fuite gro!!-loo9ing. uc9ily, you c#n 6r#p up the cre#tion o' the #nony*ou! 'unction.
1de('n#artist-selector#1artist3 ##NC1lambda#1cd3#1e@'al#1get(#cd#:artist3#artist333
&hi! i! # 'unction th#t return! # 'unction #nd one th#t re'erence! # ?#ri#ble th#t--it !ee*!--6on@t e.i!t #'ter artist-selector return!.0 It *#y !ee* odd no6, but it #ctu#lly 6or9! <u!t the 6#y you@d 6#nt--i' you c#ll artist-selector 6ith #n #rgu*ent o' 4<i)ie#$hic&s4, you get #n #nony*ou! 'unction th#t *#tche! C+! 6ho!e :artist 'ield i! 4<i)ie#$hic&s4, #nd i' you c#ll it 6ith 4L?le#Lovett4, you get # di''erent 'unction th#t 6ill *#tch #g#in!t #n :artist 'ield o' 4L?le#Lovett4. So no6 you c#n re6rite the c#ll to select li9e thi!:
$L-+,-./#1select#1artist-selector#4<i)ie#$hic&s433 11:F9FL-#4:ome4#:I.F9,F#4<i)ie#$hic&s4#:.IF98J#9#:.9TT-<#F3 #1:F9FL-#4El?4#:I.F9,F#4<i)ie#$hic&s4#:.IF98J#R#:.9TT-<#F33
:o6 you <u!t need !o*e *ore 'unction! to gener#te !elector!. 7ut <u!t #! you don@t 6#nt to h#?e to 6rite select-b?-title, select-b?-rating, #nd !o on, bec#u!e they 6ould #ll be Fuite !i*il#r, you@re not going to 6#nt to 6rite # bunch o' ne#rly identic#l !elector-'unction gener#tor!, one 'or e#ch 'ield. Why not 6rite one gener#l-purpo!e !elector-'unction gener#tor, # 'unction th#t, depending on 6h#t #rgu*ent! you p#!! it, 6ill gener#te # !elector 'unction 'or di''erent 'ield! or *#ybe e?en # co*bin#tion o' 'ield!" 4ou c#n 6rite !uch # 'unction, but 'ir!t you need # cr#!h cour!e in # 'e#ture c#lled $e0word parameters. In the 'unction! you@?e 6ritten !o '#r, you@?e !peci'ied # !i*ple li!t o' p#r#*eter!, 6hich #re bound to the corre!ponding #rgu*ent! in the c#ll to the 'unction. /or in!t#nce, the 'ollo6ing 'unction:
1de('n#(oo#1a#b#c3#1list#a#b#c33
h#! three p#r#*eter!, a, b, #nd c, #nd *u!t be c#lled 6ith three #rgu*ent!. 7ut !o*eti*e! you *#y 6#nt to 6rite # 'unction th#t c#n be c#lled 6ith ?#rying nu*ber! o' #rgu*ent!. Ley6ord p#r#*eter! #re one 6#y to #chie?e thi!. % ?er!ion o' (oo th#t u!e! 9ey6ord p#r#*eter! *ight loo9 li9e thi!:
1de('n#(oo#1>&e?#a#b#c3#1list#a#b#c33
&he only di''erence i! the >&e? #t the beginning o' the #rgu*ent li!t. >o6e?er, the c#ll! to thi! ne6 (oo 6ill loo9 Fuite di''erent. &he!e #re #ll leg#l c#ll! 6ith the re!ult to the right o' the UUV:
1(oo#:a#0#:b#!#:c#33##==/#10#!#33 1(oo#:c#3#:b#!#:a#03##==/#10#!#33 1(oo#:a#0#:c#33#######==/#10#89L#33 1(oo3#################==/#189L#89L#89L3
%! the!e e.#*ple! !ho6, the ?#lue o' the ?#ri#ble! a, b, #nd c #re bound to the ?#lue! th#t 'ollo6 the corre!ponding 9ey6ord. %nd i' # p#rticul#r 9ey6ord i!n@t pre!ent in the c#ll, the corre!ponding ?#ri#ble i! !et to NIL. I@* glo!!ing o?er # bunch o' det#il! o' ho6 9ey6ord p#r#*eter! #re !peci'ied #nd ho6 they rel#te to other 9ind! o' p#r#*eter!, but you need to 9no6 one *ore det#il. :or*#lly i' # 'unction i! c#lled 6ith no #rgu*ent 'or # p#rticul#r 9ey6ord p#r#*eter, the p#r#*eter 6ill h#?e the ?#lue NIL. >o6e?er, !o*eti*e! you@ll 6#nt to be #ble to di!tingui!h bet6een # NIL th#t 6#! e.plicitly p#!!ed #! the #rgu*ent to # 9ey6ord p#r#*eter #nd the de'#ult ?#lue NIL. &o #llo6 thi!, 6hen you !peci'y # 9ey6ord p#r#*eter you c#n repl#ce the !i*ple n#*e 6ith # li!t con!i!ting o' the n#*e o' the p#r#*eter, # de'#ult ?#lue, #nd #nother p#r#*eter n#*e, c#lled # supplied)p p#r#*eter. &he !upplied-p p#r#*eter 6ill be !et to true or '#l!e depending on 6hether #n #rgu*ent 6#! #ctu#lly p#!!ed 'or th#t 9ey6ord p#r#*eter in # p#rticul#r c#ll to the 'unction. >ere@! # ?er!ion o' (oo th#t u!e! thi! 'e#ture:
1de('n#(oo#1>&e?#a#1b#! 3#1c#3 #c-p33#1list#a#b#c#c-p33
&he gener#l !elector-'unction gener#tor, 6hich you c#n c#ll where 'or re#!on! th#t 6ill !oon beco*e #pp#rent i' you@re '#*ili#r 6ith SM d#t#b#!e!, i! # 'unction th#t t#9e! 'our 9ey6ord p#r#*eter! corre!ponding to the 'ield! in our C+ record! #nd gener#te! # !elector 'unction th#t !elect! #ny C+! th#t *#tch #ll the ?#lue! gi?en to where. /or in!t#nce, it 6ill let you !#y thing! li9e thi!:
1select#1where#:artist#4<i)ie#$hic&s433
or thi!:
1select#1where#:rating#0 #:ripped#nil33
&hi! 'unction return! #n #nony*ou! 'unction th#t return! the logic#l I8< o' one cl#u!e per 'ield in our
C+ record!. (#ch cl#u!e chec9! i' the #ppropri#te #rgu*ent 6#! p#!!ed in #nd then either co*p#re! it to the ?#lue in the corre!ponding 'ield in the C+ record or return! t, i!p@! ?er!ion o' truth, i' the p#r#*eter 6#!n@t p#!!ed in. &hu!, the !elector 'unction 6ill return t only 'or C+! th#t *#tch #ll the #rgu*ent! p#!!ed to where.2 :ote th#t you need to u!e # three-ite* li!t to !peci'y the 9ey6ord p#r#*eter ripped bec#u!e you need to 9no6 6hether the c#ller #ctu#lly p#!!ed :ripped#nil, *e#ning, HSelect C+! 6ho!e ripped 'ield i! nil,H or 6hether they le't out :ripped #ltogether, *e#ning HI don@t c#re 6h#t the ?#lue o' the ripped 'ield i!.H
5ne other ne6 bit here i! the u!e o' SETF on # co*ple. 'or* !uch #! 1get(#row#:title3. I@ll di!cu!! SETF in gre#ter det#il in Ch#pter 0, but 'or no6 you <u!t need to 9no6 th#t it@! # gener#l #!!ign*ent oper#tor th#t c#n be u!ed to #!!ign lot! o' Hpl#ce!H other th#n <u!t ?#ri#ble!. BIt@! # coincidence th#t SETF #nd GETF h#?e !uch !i*il#r n#*e!--they don@t h#?e #ny !peci#l rel#tion!hip.C /or no6 it@! enough to 9no6 th#t #'ter 1set(#1get(#row#:title3#title3, the pli!t re'erenced by ro6 6ill h#?e the ?#lue o' the ?#ri#ble title 'ollo6ing the property n#*e :title. With thi! 'pdate 'unction i' you decide th#t you reall0 dig the +i.ie Chic9! #nd th#t #ll their #lbu*! !hould go to 11, you c#n e?#lu#te the 'ollo6ing 'or*:
$L-+,-./#1'pdate#1where#:artist#4<i)ie#$hic&s43#:rating#003 89L
%nd it i! !o.
$L-+,-./#1select#1where#:artist#4<i)ie#$hic&s433 11:F9FL-#4:ome4#:I.F9,F#4<i)ie#$hic&s4#:.IF98J#00#:.9TT-<#F3 #1:F9FL-#4El?4#:I.F9,F#4<i)ie#$hic&s4#:.IF98J#00#:.9TT-<#F33
4ou c#n e?en *ore e#!ily #dd # 'unction to delete ro6! 'ro* the d#t#b#!e.
1de('n#delete-rows#1selector-(n3 ##1set(#UdbU#1remove-i(#selector-(n#UdbU333
&he 'unction REMOVE-IF i! the co*ple*ent o' REMOVE-IF-NOTG it return! # li!t 6ith #ll the ele*ent! th#t do *#tch the predic#te re*o?ed. i9e REMOVE-IF-NOT, it doe!n@t #ctu#lly #''ect the li!t it@! p#!!ed but by !#?ing the re!ult b#c9 into UdbU, delete-rows, #ctu#lly ch#nge! the content! o' the d#t#b#!e.)
$ight no6 it@! not !o b#d, but li9e #ll code duplic#tion it h#! the !#*e co!t: i' you 6#nt to ch#nge ho6 it 6or9!, you h#?e to ch#nge *ultiple copie!. %nd i' you ch#nge the 'ield! in # C+, you@ll h#?e to #dd or re*o?e cl#u!e! to where. %nd 'pdate !u''er! 'ro* the !#*e 9ind o' duplic#tion. It@! doubly #nnoying !ince the 6hole point o' the where 'unction i! to dyn#*ic#lly gener#te # bit o' code th#t chec9! the ?#lue! you c#re #boutG 6hy !hould it h#?e to do 6or9 #t runti*e chec9ing 6hether title 6#! e?en p#!!ed in" I*#gine th#t you 6ere trying to opti*iAe thi! code #nd di!co?ered th#t it 6#! !pending too *uch ti*e chec9ing 6hether title #nd the re!t o' the 9ey6ord p#r#*eter! to where 6ere e?en !et"11 I' you re#lly 6#nted to re*o?e #ll tho!e runti*e chec9!, you could go through # progr#* #nd 'ind #ll the pl#ce! you c#ll where #nd loo9 #t e.#ctly 6h#t #rgu*ent! you@re p#!!ing. &hen you could repl#ce e#ch c#ll to where 6ith #n #nony*ou! 'unction th#t doe! only the co*put#tion nece!!#ry. /or in!t#nce, i' you 'ound thi! !nippet o' code:
1select#1where#:title#4Jive#+s#a#Lrea&4#:ripped#t33
:ote th#t the #nony*ou! 'unction i! di''erent 'ro* the one th#t where 6ould h#?e returnedG you@re not trying to !#?e the c#ll to where but r#ther to pro?ide # *ore e''icient !elector 'unction. &hi! #nony*ou! 'unction h#! cl#u!e! only 'or the 'ield! th#t you #ctu#lly c#re #bout #t thi! c#ll !ite, !o it doe!n@t do #ny e.tr# 6or9 the 6#y # 'unction returned by where *ight. 4ou c#n prob#bly i*#gine going through #ll your !ource code #nd 'i.ing up #ll the c#ll! to where in thi! 6#y. 7ut you c#n prob#bly #l!o i*#gine th#t it 6ould be # huge p#in. I' there 6ere enough o' the*, #nd it 6#! i*port#nt enough, it *ight e?en be 6orth6hile to 6rite !o*e 9ind o' preproce!!or th#t con?ert! where c#ll! to the code you@d 6rite by h#nd. &he i!p 'e#ture th#t *#9e! thi! tri?i#lly e#!y i! it! *#cro !y!te*. I c#n@t e*ph#!iAe enough th#t the Co**on i!p *#cro !h#re! e!!enti#lly nothing but the n#*e 6ith the te.t-b#!ed *#cro! 'ound in C #nd CEE. Where the C pre-proce!!or oper#te! by te.tu#l !ub!titution #nd under!t#nd! #l*o!t nothing o'
the !tructure o' C #nd CEE, # i!p *#cro i! e!!enti#lly # code gener#tor th#t get! run 'or you #uto*#tic#lly by the co*piler.12 When # i!p e.pre!!ion cont#in! # c#ll to # *#cro, in!te#d o' e?#lu#ting the #rgu*ent! #nd p#!!ing the* to the 'unction, the i!p co*piler p#!!e! the #rgu*ent!, une?#lu#ted, to the *#cro code, 6hich return! # ne6 i!p e.pre!!ion th#t i! then e?#lu#ted in pl#ce o' the origin#l *#cro c#ll. I@ll !t#rt 6ith # !i*ple, #nd !illy, e.#*ple #nd then !ho6 ho6 you c#n repl#ce the where 'unction 6ith # where *#cro. 7e'ore I c#n 6rite thi! e.#*ple *#cro, I need to Fuic9ly introduce one ne6 'unction: .-K-.,- t#9e! # li!t #! #n #rgu*ent #nd return! # ne6 li!t th#t i! it! re?er!e. So 1reverse#C10#!# 333 e?#lu#te! to 13#!#03. :o6 let@! cre#te # *#cro.
1de(macro#bac&wards#1e)pr3#1reverse#e)pr33
&he *#in !ynt#ctic di''erence bet6een # 'unction #nd # *#cro i! th#t you de'ine # *#cro 6ith DEFMACRO in!te#d o' DEFUN. %'ter th#t # *#cro de'inition con!i!t! o' # n#*e, <u!t li9e # 'unction, # p#r#*eter li!t, #nd # body o' e.pre!!ion!, both #l!o li9e # 'unction. >o6e?er, # *#cro h#! # tot#lly di''erent e''ect. 4ou c#n u!e thi! *#cro #! 'ollo6!:
$L-+,-./#1bac&wards#14hello5#world4#t#(ormat33 hello5#world 89L
>o6 did th#t 6or9" When the $(P !t#rted to e?#lu#te the bac&wards e.pre!!ion, it recogniAed th#t bac&wards i! the n#*e o' # *#cro. So it le't the e.pre!!ion 14hello5#world4#t#(ormat3 une?#lu#ted, 6hich i! good bec#u!e it i!n@t # leg#l i!p 'or*. It then p#!!ed th#t li!t to the bac&wards# code. &he code in bac&wards p#!!ed the li!t to REVERSE, 6hich returned the li!t 1(ormat#t# 4hello5#world43. bac&wards then p#!!ed th#t ?#lue b#c9 out to the $(P , 6hich then e?#lu#ted it in pl#ce o' the origin#l e.pre!!ion. &he bac&wards *#cro thu! de'ine! # ne6 l#ngu#ge th#t@! # lot li9e i!p--<u!t b#c96#rd--th#t you c#n drop into #nyti*e !i*ply by 6r#pping # b#c96#rd i!p e.pre!!ion in # c#ll to the bac&wards *#cro. %nd, in # co*piled i!p progr#*, th#t ne6 l#ngu#ge i! <u!t #! e''icient #! nor*#l i!p bec#u!e #ll the *#cro code--the code th#t gener#te! the ne6 e.pre!!ion--run! #t co*pile ti*e. In other 6ord!, the co*piler 6ill gener#te e.#ctly the !#*e code 6hether you 6rite 1bac&wards#14hello5#world4# t#(ormat33 or 1(ormat#t#4hello5#world43. So ho6 doe! th#t help 6ith the code duplic#tion in where" Well, you c#n 6rite # *#cro th#t gener#te! e.#ctly the code you need 'or e#ch p#rticul#r c#ll to where. %g#in, the be!t #ppro#ch i! to build our code botto* up. In the h#nd-opti*iAed !elector 'unction, you h#d #n e.pre!!ion o' the 'ollo6ing 'or* 'or e#ch #ctu#l 'ield re'erred to in the origin#l c#ll to where:
1e@'al#1get(#cd#field3#value3
So let@! 6rite # 'unction th#t, gi?en the n#*e o' # 'ield #nd # ?#lue, return! !uch #n e.pre!!ion. Since #n e.pre!!ion i! <u!t # li!t, you *ight thin9 you could 6rite !o*ething li9e thi!:
1de('n#ma&e-comparison-e)pr#1(ield#val'e3####S#wrong ##1list#e@'al#1list#get(#cd#(ield3#val'e33
>o6e?er, there@! one tric9 here: #! you 9no6, 6hen i!p !ee! # !i*ple n#*e !uch #! (ield or val'e# other th#n #! the 'ir!t ele*ent o' # li!t, it #!!u*e! it@! the n#*e o' # ?#ri#ble #nd loo9! up it! ?#lue. &h#t@! 'ine 'or (ield #nd val'eG it@! e.#ctly 6h#t you 6#nt. 7ut it 6ill tre#t e@'al, get(, #nd cd the !#*e 6#y, 6hich isn(t 6h#t you 6#nt. >o6e?er, you #l!o 9no6 ho6 to !top i!p 'ro* e?#lu#ting #
'or*: !tic9 # !ingle 'or6#rd Fuote BCC in 'ront o' it. So i' you 6rite ma&e-comparison-e)pr li9e thi!, it 6ill do 6h#t you 6#nt:
1de('n#ma&e-comparison-e)pr#1(ield#val'e3 ##1list#Ce@'al#1list#Cget(#Ccd#(ield3#val'e33
It turn! out th#t there@! #n e?en better 6#y to do it. Wh#t you@d re#lly li9e i! # 6#y to 6rite #n e.pre!!ion th#t@! *o!tly not e?#lu#ted #nd then h#?e !o*e 6#y to pic9 out # 'e6 e.pre!!ion! th#t you do 6#nt e?#lu#ted. %nd, o' cour!e, there@! <u!t !uch # *ech#ni!*. % b#c9 Fuote BBC be'ore #n e.pre!!ion !top! e?#lu#tion <u!t li9e # 'or6#rd Fuote.
$L-+,-./#B10#!#33 10#!#33 $L-+,-./#C10#!#33 10#!#33
>o6e?er, in # b#c9-Fuoted e.pre!!ion, #ny !ube.pre!!ion th#t@! preceded by # co**# i! e?#lu#ted. :otice the e''ect o' the co**# in the !econd e.pre!!ion:
B10#!#12#0#!33########==/#10#!#12#0#!33 B10#!#512#0#!33#######==/#10#!#33
:o6 i' you loo9 b#c9 to the h#nd-opti*iAed !elector 'unction, you c#n !ee th#t the body o' the 'unction con!i!ted o' one co*p#ri!on e.pre!!ion per 'ield;?#lue p#ir, #ll 6r#pped in #n AND e.pre!!ion. %!!u*e 'or the *o*ent th#t you@ll #rr#nge 'or the #rgu*ent! to the where *#cro to be p#!!ed #! # !ingle li!t. 4ou@ll need # 'unction th#t c#n t#9e the ele*ent! o' !uch # li!t p#ir6i!e #nd collect the re!ult! o' c#lling ma&e-comparison-e)pr on e#ch p#ir. &o i*ple*ent th#t 'unction, you c#n dip into the b#g o' #d?#nced i!p tric9! #nd pull out the *ighty #nd po6er'ul L;;T *#cro.
1de('n#ma&e-comparisons-list#1(ields3 ##1loop#while#(ields #####collecting#1ma&e-comparison-e)pr#1pop#(ields3#1pop#(ields3333
% 'ull di!cu!!ion o' L;;T 6ill h#?e to 6#it until Ch#pter 22G 'or no6 <u!t note th#t thi! L;;T e.pre!!ion doe! e.#ctly 6h#t you need: it loop! 6hile there #re ele*ent! le't in the (ields li!t, popping o'' t6o #t # ti*e, p#!!ing the* to ma&e-comparison-e)pr, #nd collecting the re!ult! to be returned #t the end o' the loop. &he POP *#cro per'or*! the in?er!e oper#tion o' the T+,: *#cro you u!ed to #dd record! to UdbU. :o6 you <u!t need to 6r#p up the li!t returned by ma&e-comparison-list in #n I8< #nd #n #nony*ou! 'unction, 6hich you c#n do in the where *#cro it!el'. 8!ing # b#c9 Fuote to *#9e # te*pl#te th#t you 'ill in by interpol#ting the ?#lue o' ma&e-comparisons-list, it@! tri?i#l.
1de(macro#where#1>rest#cla'ses3
##BNC1lambda#1cd3#1and#5P1ma&e-comparisons-list#cla'ses3333
&hi! *#cro u!e! # ?#ri#nt o' 5 Bn#*ely, the 5PC be'ore the c#ll to ma&e-comparisons-list. &he 5P H!plice!H the ?#lue o' the 'ollo6ing e.pre!!ion--6hich *u!t e?#lu#te to # li!t--into the enclo!ing li!t. 4ou c#n !ee the di''erence bet6een 5 #nd 5P in the 'ollo6ing t6o e.pre!!ion!:
B1and#51list#0#!#333###==/#1I8<#10#!#333 B1and#5P1list#0#!#333##==/#1I8<#0#!#33
4ou c#n #l!o u!e 5P to !plice into the *iddle o' # li!t.
B1and#5P1list#0#!#33#43#==/#1I8<#0#!#3#43
&he other i*port#nt 'e#ture o' the where *#cro i! the u!e o' >rest in the #rgu*ent li!t. i9e >&e?, >rest *odi'ie! the 6#y #rgu*ent! #re p#r!ed. With # >rest in it! p#r#*eter li!t, # 'unction or *#cro c#n t#9e #n #rbitr#ry nu*ber o' #rgu*ent!, 6hich #re collected into # !ingle li!t th#t beco*e! the ?#lue o' the ?#ri#ble 6ho!e n#*e 'ollo6! the >rest. So i' you c#ll where li9e thi!:
1where#:title#4Jive#+s#a#Lrea&4#:ripped#t3
&hi! li!t i! p#!!ed to ma&e-comparisons-list, 6hich return! # li!t o' co*p#ri!on e.pre!!ion!. 4ou c#n !ee e.#ctly 6h#t code # c#ll to where 6ill gener#te u!ing the 'unction MACROEXPAND-1. I' you p#!! MACROEXPAND-1, # 'or* repre!enting # *#cro c#ll, it 6ill c#ll the *#cro code 6ith #ppropri#te #rgu*ent! #nd return the e.p#n!ion. So you c#n chec9 out the pre?iou! where c#ll li9e thi!:
$L-+,-./#1macroe)pand-0#C1where#:title#4Jive#+s#a#Lrea&4#:ripped#t33 NC1LI%L<I#1$<3 ####1I8<#1-Z+IL#1J-FE#$<#:F9FL-3#4Jive#+s#a#Lrea&43 #########1-Z+IL#1J-FE#$<#:.9TT-<3#F333 F
It 6or9!. %nd the where *#cro 6ith it! t6o helper 'unction! i! #ctu#lly one line !horter th#n the old where 'unction. %nd it@! *ore gener#l in th#t it@! no longer tied to the !peci'ic 'ield! in our C+ record!.
Wrapping 'p
:o6, #n intere!ting thing h#! h#ppened. 4ou re*o?ed duplic#tion #nd *#de the code *ore e''icient and *ore gener#l #t the !#*e ti*e. &h#t@! o'ten the 6#y it goe! 6ith # 6ell-cho!en *#cro. &hi! *#9e! !en!e bec#u!e # *#cro i! <u!t #nother *ech#ni!* 'or cre#ting #b!tr#ction!--#b!tr#ction #t the !ynt#ctic le?el, #nd #b!tr#ction! #re by de'inition *ore conci!e 6#y! o' e.pre!!ing underlying gener#litie!. :o6 the only code in the *ini-d#t#b#!e th#t@! !peci'ic to C+! #nd the 'ield! in the* i! in the ma&e-cd, prompt-(or-cd, #nd add-cd 'unction!. In '#ct, our ne6 where *#cro 6ould 6or9 6ith #ny pli!t-
b#!ed d#t#b#!e. >o6e?er, thi! i! !till '#r 'ro* being # co*plete d#t#b#!e. 4ou c#n prob#bly thin9 o' plenty o' 'e#ture! to #dd, !uch #! !upporting *ultiple t#ble! or *ore el#bor#te Fuerie!. In Ch#pter 22 6e@ll build #n 3P3 d#t#b#!e th#t incorpor#te! !o*e o' tho!e 'e#ture!. &he point o' thi! ch#pter 6#! to gi?e you # Fuic9 introduction to <u!t # h#nd'ul o' i!p@! 'e#ture! #nd !ho6 ho6 they@re u!ed to 6rite code th#t@! # bit *ore intere!ting th#n Hhello, 6orld.H In the ne.t ch#pter 6e@ll begin # *ore !y!te*#tic o?er?ie6 o' i!p.
17e'ore 28!ing
I proceed, ho6e?er, it@! cruci#lly i*port#nt th#t you 'orget #nything you *#y 9no6 #bout Ide'ine-!tyle H*#cro!H #! i*ple*ented in the C pre-proce!!or. i!p *#cro! #re # tot#lly di''erent be#!t. # glob#l ?#ri#ble #l!o h#! !o*e dr#6b#c9!--'or in!t#nce, you c#n h#?e only one d#t#b#!e #t # ti*e. In Ch#pter 22, 6ith *ore o' the l#ngu#ge under your belt, you@ll be re#dy to build # *ore 'le.ible d#t#b#!e. 4ou@ll #l!o !ee, in Ch#pter 0, ho6 e?en u!ing # glob#l ?#ri#ble i! *ore 'le.ible in Co**on i!p th#n it *#y be in other l#ngu#ge!.
35ne
o' the coole!t FORMAT directi?e! i! the 7. directi?e. (?er 6#nt to 9no6 ho6 to !#y # re#lly big nu*ber in (ngli!h 6ord!" i!p 9no6!. (?#lu#te thi!:
1(ormat#nil#47r4#06 693R 44!"R99 !Q""4096! 9!3
#nd you !hould get b#c9 B6r#pped 'or legibilityC: Hone octillion !i. hundred !i. !eptillion nine hundred thirty-eight !e.tillion 'orty-'our Fuintillion t6o hundred 'i'ty-eight Fu#drillion nine hundred ninety trillion t6o hundred !e?enty-'i?e billion 'i?e hundred 'orty-one *illion nine hundred !i.ty-t6o thou!#nd ninetyt6oH
-Windo6!
#ctu#lly under!t#nd! 'or6#rd !l#!he! in 'ilen#*e! e?en though it nor*#lly u!e! # b#c9!l#!h #! the directory !ep#r#tor. &hi! i! con?enient !ince other6i!e you h#?e to 6rite double b#c9!l#!he! bec#u!e b#c9!l#!h i! the e!c#pe ch#r#cter in i!p !tring!.
5&he 0&he
6ord l#*bd# i! u!ed in i!p bec#u!e o' #n e#rly connection to the l#*bd# c#lculu!, # *#the*#tic#l 'or*#li!* in?ented 'or !tudying *#the*#tic#l 'unction!. technic#l ter* 'or # 'unction th#t re'erence! # ?#ri#ble in it! enclo!ing !cope i! # clo!ure bec#u!e the 'unction Hclo!e! o?erH the ?#ri#ble. I@ll di!cu!! clo!ure! in *ore det#il in Ch#pter 0.
2:ote
th#t in i!p, #n I/ 'or*, li9e e?erything el!e, i! #n e.pre!!ion th#t return! # ?#lue. It@! #ctu#lly *ore li9e the tern#ry oper#tor B?:C in Perl, D#?#, #nd C in th#t thi! i! leg#l in tho!e l#ngu#ge!:
some=var#=#some=boolean#?#val'e0#:#val'e!S
need to u!e the n#*e delete-rows r#ther th#n the *ore ob?iou! delete bec#u!e there@! #lre#dy # 'unction in Co**on i!p c#lled DELETE. &he i!p p#c9#ge !y!te* gi?e! you # 6#y to de#l 6ith !uch n#*ing con'lict!, !o you could h#?e # 'unction n#*ed delete i' you 6#nted. 7ut I@* not
you@re 6orried th#t thi! code cre#te! # *e*ory le#9, re!t #!!ured: i!p 6#! the l#ngu#ge th#t in?ented g#rb#ge collection B#nd he#p #lloc#tion 'or th#t *#tterC. &he *e*ory u!ed by the old ?#lue o' UdbU 6ill be #uto*#tic#lly recl#i*ed, #!!u*ing no one el!e i! holding on to # re'erence to it, 6hich none o' thi! code i!.
10% 'riend
o' *ine 6#! once inter?ie6ing #n engineer 'or # progr#**ing <ob #nd #!9ed hi* # typic#l inter?ie6 Fue!tion: ho6 do you 9no6 6hen # 'unction or *ethod i! too big" Well, !#id the c#ndid#te, I don@t li9e #ny *ethod to be bigger th#n *y he#d. 4ou *e#n you c#n@t 9eep #ll the det#il! in your he#d" :o, I *e#n I put *y he#d up #g#in!t *y *onitor, #nd the code !houldn@t be bigger th#n *y he#d.
11It@!
unli9ely th#t the co!t o' chec9ing 6hether 9ey6ord p#r#*eter! h#d been p#!!ed 6ould be # detectible dr#g on per'or*#nce !ince chec9ing 6hether # ?#ri#ble i! 89L i! going to be pretty che#p. 5n the other h#nd, the!e 'unction! returned by where #re going to be right in the *iddle o' the inner loop o' #ny select, 'pdate, or delete-rows c#ll, #! they h#?e to be c#lled once per entry in the d#t#b#!e. %ny6#y, 'or illu!tr#ti?e purpo!e!, thi! 6ill h#?e to do.
123#cro!
#re #l!o run by the interpreter--ho6e?er, it@! e#!ier to under!t#nd the point o' *#cro! 6hen you thin9 #bout co*piled code. %! 6ith e?erything el!e in thi! ch#pter, I@ll co?er thi! in gre#ter det#il in 'uture ch#pter!.
li9e the #b!tr#ct !ynt#. tree gener#ted by the p#r!er! 'or non- i!p l#ngu#ge!. &he e?#lu#tor then de'ine! # !ynt#. o' i!p forms th#t c#n be built out o' !-e.pre!!ion!. :ot #ll !e.pre!!ion! #re leg#l i!p 'or*! #ny *ore th#n #ll !eFuence! o' ch#r#cter! #re leg#l !-e.pre!!ion!. /or in!t#nce, both 1(oo#0#!3 #nd 14(oo4#0#!3 #re !-e.pre!!ion!, but only the 'or*er c#n be # i!p 'or* !ince # li!t th#t !t#rt! 6ith # !tring h#! no *e#ning #! # i!p 'or*. &hi! !plit o' the bl#c9 bo. h#! # couple o' con!eFuence!. 5ne i! th#t you c#n u!e !-e.pre!!ion!, #! you !#6 in Ch#pter 3, #! #n e.tern#liA#ble d#t# 'or*#t 'or d#t# other th#n !ource code, u!ing READ to re#d it #nd PRINT to print it.- &he other con!eFuence i! th#t !ince the !e*#ntic! o' the l#ngu#ge #re de'ined in ter*! o' tree! o' ob<ect! r#ther th#n !tring! o' ch#r#cter!, it@! e#!ier to gener#te code 6ithin the l#ngu#ge th#n it 6ould be i' you h#d to gener#te code #! te.t. =ener#ting code co*pletely 'ro* !cr#tch i! only *#rgin#lly e#!ier--building up li!t! ?!. building up !tring! i! #bout the !#*e #*ount o' 6or9. &he re#l 6in, ho6e?er, i! th#t you c#n gener#te code by *#nipul#ting e.i!ting d#t#. &hi! i! the b#!i! 'or i!p@! *#cro!, 6hich I@ll di!cu!! in *uch *ore det#il in 'uture ch#pter!. /or no6 I@ll 'ocu! on the t6o le?el! o' !ynt#. de'ined by Co**on i!p: the !ynt#. o' !-e.pre!!ion! under!tood by the re#der #nd the !ynt#. o' i!p 'or*! under!tood by the e?#lu#tor.
/4e)pressions
&he b#!ic ele*ent! o' !-e.pre!!ion! #re lists #nd atoms. i!t! #re deli*ited by p#renthe!e! #nd c#n cont#in #ny nu*ber o' 6hite!p#ce-!ep#r#ted ele*ent!. %to*! #re e?erything el!e.5 &he ele*ent! o' li!t! #re the*!el?e! !-e.pre!!ion! Bin other 6ord!, #to*! or ne!ted li!t!C. Co**ent!--6hich #ren@t, technic#lly !pe#9ing, !-e.pre!!ion!--!t#rt 6ith # !e*icolon, e.tend to the end o' # line, #nd #re tre#ted e!!enti#lly li9e 6hite!p#ce. %nd th#t@! pretty *uch it. Since li!t! #re !ynt#ctic#lly !o tri?i#l, the only re*#ining !ynt#ctic rule! you need to 9no6 #re tho!e go?erning the 'or* o' di''erent 9ind! o' #to*!. In thi! !ection I@ll de!cribe the rule! 'or the *o!t co**only u!ed 9ind! o' #to*!: nu*ber!, !tring!, #nd n#*e!. %'ter th#t, I@ll co?er ho6 !-e.pre!!ion! co*po!ed o' the!e ele*ent! c#n be e?#lu#ted #! i!p 'or*!. :u*ber! #re '#irly !tr#ight'or6#rd: #ny !eFuence o' digit!--po!!ibly pre'#ced 6ith # !ign B2 or -C, cont#ining # deci*#l point B.C or # !olidu! B/C, or ending 6ith #n e.ponent *#r9er--i! re#d #! # nu*ber. /or e.#*ple:
0!3#######S#the#integer#one#h'ndred#twent?-three 3/Q#######S#the#ratio#three-sevenths 0. #######S#the#(loating-point#n'mber#one#in#de(a'lt#precision 0. e #####S#another#wa?#to#write#the#same#(loating-point#n'mber 0. d #####S#the#(loating-point#n'mber#one#in#4do'ble4#precision 0. e-4####S#the#(loating-point#e@'ivalent#to#one-ten-tho'sandth 24!#######S#the#integer#(ort?-two -4!#######S#the#integer#negative#(ort?-two -0/4######S#the#ratio#negative#one-@'arter -!/R######S#another#wa?#to#write#negative#one-@'arter !46/!#####S#another#wa?#to#write#the#integer#one#h'ndred#twent?-three
&he!e di''erent 'or*! repre!ent di''erent 9ind! o' nu*ber!: integer!, r#tio!, #nd 'lo#ting point. i!p #l!o !upport! co*ple. nu*ber!, 6hich h#?e their o6n not#tion #nd 6hich I@ll di!cu!! in Ch#pter 10. %! !o*e o' the!e e.#*ple! !ugge!t, you c#n not#te the !#*e nu*ber in *#ny 6#y!. 7ut reg#rdle!! o' ho6 you 6rite the*, #ll r#tion#l!--integer! #nd r#tio!--#re repre!ented intern#lly in H!i*pli'iedH 'or*. In other 6ord!, the ob<ect! th#t repre!ent -2;, or 2-0;2 #ren@t di!tinct 'ro* the ob<ect! th#t repre!ent
-1;- #nd 123. Si*il#rly, 0. #nd 0. e #re <u!t di''erent 6#y! o' 6riting the !#*e nu*ber. 5n the other h#nd, 0. , 0. d , #nd 0 c#n #ll denote di''erent ob<ect! bec#u!e the di''erent 'lo#ting-point repre!ent#tion! #nd integer! #re di''erent type!. We@ll !#?e the det#il! #bout the ch#r#cteri!tic! o' di''erent 9ind! o' nu*ber! 'or Ch#pter 10. String! liter#l!, #! you !#6 in the pre?iou! ch#pter, #re enclo!ed in double Fuote!. Within # !tring # b#c9!l#!h BYC e!c#pe! the ne.t ch#r#cter, c#u!ing it to be included in the !tring reg#rdle!! o' 6h#t it i!. &he only t6o ch#r#cter! th#t must be e!c#ped 6ithin # !tring #re double Fuote! #nd the b#c9!l#!h it!el'. %ll other ch#r#cter! c#n be included in # !tring liter#l 6ithout e!c#ping, reg#rdle!! o' their *e#ning out!ide # !tring. So*e e.#*ple !tring liter#l! #re #! 'ollo6!:
4(oo4#####S#the#string#containing#the#characters#(5#o5#and#o. 4(oYo4####S#the#same#string 4(oYYo4###S#the#string#containing#the#characters#(5#o5#Y5#and#o. 4(oY4o4###S#the#string#containing#the#characters#(5#o5#45#and#o.
:#*e! u!ed in i!p progr#*!, !uch #! FORMAT #nd hello-world, #nd UdbU #re repre!ented by ob<ect! c#lled s0mbols. &he re#der 9no6! nothing #bout ho6 # gi?en n#*e i! going to be u!ed-6hether it@! the n#*e o' # ?#ri#ble, # 'unction, or !o*ething el!e. It <u!t re#d! # !eFuence o' ch#r#cter! #nd build! #n ob<ect to repre!ent the n#*e.0 %l*o!t #ny ch#r#cter c#n #ppe#r in # n#*e. White!p#ce ch#r#cter! c#n@t, though, bec#u!e the ele*ent! o' li!t! #re !ep#r#ted by 6hite!p#ce. +igit! c#n #ppe#r in n#*e! #! long #! the n#*e #! # 6hole c#n@t be interpreted #! # nu*ber. Si*il#rly, n#*e! c#n cont#in period!, but the re#der c#n@t re#d # n#*e th#t con!i!t! only o' period!. &en ch#r#cter! th#t !er?e other !ynt#ctic purpo!e! c#n@t #ppe#r in n#*e!: open #nd clo!e p#renthe!e!, double #nd !ingle Fuote!, b#c9tic9, co**#, colon, !e*icolon, b#c9!l#!h, #nd ?ertic#l b#r. %nd e?en tho!e ch#r#cter! can, i' you@re 6illing to e!c#pe the* by preceding the ch#r#cter to be e!c#ped 6ith # b#c9!l#!h or by !urrounding the p#rt o' the n#*e cont#ining ch#r#cter! th#t need e!c#ping 6ith ?ertic#l b#r!. &6o i*port#nt ch#r#cteri!tic! o' the 6#y the re#der tr#n!l#te! n#*e! to !y*bol ob<ect! h#?e to do 6ith ho6 it tre#t! the c#!e o' letter! in n#*e! #nd ho6 it en!ure! th#t the !#*e n#*e i! #l6#y! re#d #! the !#*e !y*bol. While re#ding n#*e!, the re#der con?ert! #ll une!c#ped ch#r#cter! in # n#*e to their upperc#!e eFui?#lent!. &hu!, the re#der 6ill re#d (oo, Eoo, #nd E;; #! the !#*e !y*bol: E;;. >o6e?er, Y(YoYo #nd X(ooX 6ill both be re#d #! (oo, 6hich i! # di''erent ob<ect th#n the !y*bol E;;. &hi! i! 6hy 6hen you de'ine # 'unction #t the $(P #nd it print! the n#*e o' the 'unction, it@! been con?erted to upperc#!e. St#nd#rd !tyle, the!e d#y!, i! to 6rite code in #ll lo6erc#!e #nd let the re#der ch#nge n#*e! to upperc#!e.2 &o en!ure th#t the !#*e te.tu#l n#*e i! #l6#y! re#d #! the !#*e !y*bol, the re#der interns !y*bol!-#'ter it h#! re#d the n#*e #nd con?erted it to #ll upperc#!e, the re#der loo9! in # t#ble c#lled # pac$age 'or #n e.i!ting !y*bol 6ith the !#*e n#*e. I' it c#n@t 'ind one, it cre#te! # ne6 !y*bol #nd #dd! it to the t#ble. 5ther6i!e, it return! the !y*bol #lre#dy in the t#ble. &hu!, #ny6here the !#*e n#*e #ppe#r! in #ny !-e.pre!!ion, the !#*e ob<ect 6ill be u!ed to repre!ent it., 7ec#u!e n#*e! c#n cont#in *#ny *ore ch#r#cter! in i!p th#n they c#n in %lgol-deri?ed l#ngu#ge!, cert#in n#*ing con?ention! #re di!tinct to i!p, !uch #! the u!e o' hyphen#ted n#*e! li9e helloworld. %nother i*port#nt con?ention i! th#t glob#l ?#ri#ble! #re gi?en n#*e! th#t !t#rt #nd end 6ith U. Si*il#rly, con!t#nt! #re gi?en n#*e! !t#rting #nd ending in 2. %nd !o*e progr#**er! 6ill n#*e p#rticul#rly lo6-le?el 'unction! 6ith n#*e! th#t !t#rt 6ith 6 or e?en 66. &he n#*e! de'ined in the l#ngu#ge !t#nd#rd u!e only the #lph#betic ch#r#cter! B%-RC plu! U, 2, -, /, 0, !, O, =, /, #nd >. &he !ynt#. 'or li!t!, nu*ber!, !tring!, #nd !y*bol! c#n de!cribe # good percent#ge o' i!p progr#*!. 5ther rule! de!cribe not#tion! 'or liter#l ?ector!, indi?idu#l ch#r#cter!, #nd #rr#y!, 6hich I@ll co?er
6hen I t#l9 #bout the #!!oci#ted d#t# type! in Ch#pter! 10 #nd 11. /or no6 the 9ey thing to under!t#nd i! ho6 you c#n co*bine nu*ber!, !tring!, #nd !y*bol! 6ith p#renthe!e!-deli*ited li!t! to build !e.pre!!ion! repre!enting #rbitr#ry tree! o' ob<ect!. So*e !i*ple e.#*ple! loo9 li9e thi!:
)#############S#the#s?mbol#[ 13############S#the#empt?#list 10#!#33#######S#a#list#o(#three#n'mbers 14(oo4#4bar43#S#a#list#o(#two#strings 1)#?#*3#######S#a#list#o(#three#s?mbols 1)#0#4(oo43###S#a#list#o(#a#s?mbol5#a#n'mber5#and#a#string 12#1U#!#33#43#S#a#list#o(#a#s?mbol5#a#list5#and#a#n'mber.
%n only !lightly *ore co*ple. e.#*ple i! the 'ollo6ing 'our-ite* li!t th#t cont#in! t6o !y*bol!, the e*pty li!t, #nd #nother li!t, it!el' cont#ining t6o !y*bol! #nd # !tring:
1de('n#hello-world#13 ##1(ormat#t#4hello5#world433
When the re#der intern! !uch # n#*e, it #uto*#tic#lly de'ine! # con!t#nt ?#ri#ble 6ith the n#*e #nd 6ith the !y*bol #! the ?#lue. &hing! get *ore intere!ting 6hen 6e con!ider ho6 li!t! #re e?#lu#ted. %ll leg#l li!t 'or*! !t#rt 6ith # !y*bol, but three 9ind! o' li!t 'or*! #re e?#lu#ted in three Fuite di''erent 6#y!. &o deter*ine 6h#t 9ind o' 'or* # gi?en li!t i!, the e?#lu#tor *u!t deter*ine 6hether the !y*bol th#t !t#rt! the li!t i! the n#*e o' # 'unction, # *#cro, or # !peci#l oper#tor. I' the !y*bol h#!n@t been de'ined yet--#! *#y be the c#!e i' you@re co*piling code th#t cont#in! re'erence! to 'unction! th#t 6ill be de'ined l#ter--it@! #!!u*ed to be # 'unction n#*e.12 I@ll re'er to the three 9ind! o' 'or*! #! function call forms, macro forms, #nd special forms.
Function #a%%s
&he e?#lu#tion rule 'or 'unction c#ll 'or*! i! !i*ple: e?#lu#te the re*#ining ele*ent! o' the li!t #! i!p 'or*! #nd p#!! the re!ulting ?#lue! to the n#*ed 'unction. &hi! rule ob?iou!ly pl#ce! !o*e #ddition#l !ynt#ctic con!tr#int! on # 'unction c#ll 'or*: #ll the ele*ent! o' the li!t #'ter the 'ir!t *u!t the*!el?e! be 6ell-'or*ed i!p 'or*!. In other 6ord!, the b#!ic !ynt#. o' # 'unction c#ll 'or* i! #! 'ollo6!, 6here e#ch o' the #rgu*ent! i! it!el' # i!p 'or*:
1function-name#argumentU3
&hu!, the 'ollo6ing e.pre!!ion i! e?#lu#ted by 'ir!t e?#lu#ting 0, then e?#lu#ting !, #nd then p#!!ing the re!ulting ?#lue! to the + 'unction, 6hich return! 3:
12#0#!3
% *ore co*ple. e.pre!!ion !uch #! the 'ollo6ing i! e?#lu#ted in !i*il#r '#!hion e.cept th#t e?#lu#ting the #rgu*ent! 12#0#!3 #nd 1-#3#43 ent#il! 'ir!t e?#lu#ting their #rgu*ent! #nd #pplying the #ppropri#te 'unction! to the*:
1U#12#0#!3#1-#3#433
(?entu#lly, the ?#lue! 3 #nd -1 #re p#!!ed to the * 'unction, 6hich return! -3. %! the!e e.#*ple! !ho6, 'unction! #re u!ed 'or *#ny o' the thing! th#t reFuire !peci#l !ynt#. in other l#ngu#ge!. &hi! help! 9eep i!p@! !ynt#. regul#r.
/pecia% 7perators
&h#t !#id, not #ll oper#tion! c#n be de'ined #! 'unction!. 7ec#u!e #ll the #rgu*ent! to # 'unction #re e?#lu#ted be'ore the 'unction i! c#lled, there@! no 6#y to 6rite # 'unction th#t beh#?e! li9e the IF oper#tor you u!ed in Ch#pter 3. &o !ee 6hy, con!ider thi! 'or*:
1i(#)#1(ormat#t#4?es43#1(ormat#t#4no433
I' IF 6ere # 'unction, the e?#lu#tor 6ould e?#lu#te the #rgu*ent e.pre!!ion! 'ro* le't to right. &he !y*bol ) 6ould be e?#lu#ted #! # ?#ri#ble yielding !o*e ?#lueG then 1(ormat#t#4?es43 6ould be e?#lu#ted #! # 'unction c#ll, yielding NIL #'ter printing Hye!H to !t#nd#rd output. &hen 1(ormat#t# 4no43 6ould be e?#lu#ted, printing HnoH #nd #l!o yielding NIL. 5nly #'ter #ll three e.pre!!ion! 6ere e?#lu#ted 6ould the re!ulting ?#lue! be p#!!ed to IF, too l#te 'or it to control 6hich o' the t6o FORMAT e.pre!!ion! get! e?#lu#ted.
&o !ol?e thi! proble*, Co**on i!p de'ine! # couple doAen !o-c#lled !peci#l oper#tor!, IF being one, th#t do thing! th#t 'unction! c#n@t do. &here #re 25 in #ll, but only # !*#ll h#nd'ul #re u!ed directly in d#y-to-d#y progr#**ing.13 When the 'ir!t ele*ent o' # li!t i! # !y*bol n#*ing # !peci#l oper#tor, the re!t o' the e.pre!!ion! #re e?#lu#ted #ccording to the rule 'or th#t oper#tor. &he rule 'or IF i! pretty e#!y: e?#lu#te the 'ir!t e.pre!!ion. I' it e?#lu#te! to non-NIL, then e?#lu#te the ne.t e.pre!!ion #nd return it! ?#lue. 5ther6i!e, return the ?#lue o' e?#lu#ting the third e.pre!!ion or NIL i' the third e.pre!!ion i! o*itted. In other 6ord!, the b#!ic 'or* o' #n IF e.pre!!ion i! #! 'ollo6!:
1i(#test-form#then-form#D#else-form#G3
&he test)form 6ill #l6#y! be e?#lu#ted #nd then one or the other o' the then)form or else)form. %n e?en !i*pler !peci#l oper#tor i! QUOTE, 6hich t#9e! # !ingle e.pre!!ion #! it! H#rgu*entH #nd !i*ply return! it, une?#lu#ted. /or in!t#nce, the 'ollo6ing e?#lu#te! to the li!t 12#0#!3, not the ?#lue 3:
1@'ote#12#0#!33
&here@! nothing !peci#l #bout thi! li!tG you c#n *#nipul#te it <u!t li9e #ny li!t you could cre#te 6ith the LIST 'unction.1QUOTE i! u!ed co**only enough th#t # !peci#l !ynt#. 'or it i! built into the re#der. In!te#d o' 6riting the 'ollo6ing:
1@'ote#12#0#!33
&hi! !ynt#. i! # !*#ll e.ten!ion o' the !-e.pre!!ion !ynt#. under!tood by the re#der. /ro* the point o' ?ie6 o' the e?#lu#tor, both tho!e e.pre!!ion! 6ill loo9 the !#*e: # li!t 6ho!e 'ir!t ele*ent i! the !y*bol QUOTE #nd 6ho!e !econd ele*ent i! the li!t 12#0#!3.15 In gener#l, the !peci#l oper#tor! i*ple*ent 'e#ture! o' the l#ngu#ge th#t reFuire !o*e !peci#l proce!!ing by the e?#lu#tor. /or in!t#nce, !e?er#l !peci#l oper#tor! *#nipul#te the en?iron*ent in 6hich other 'or*! 6ill be e?#lu#ted. 5ne o' the!e, 6hich I@ll di!cu!! in det#il in Ch#pter 0, i! LET, 6hich i! u!ed to cre#te ne6 ?#ri#ble binding!. &he 'ollo6ing 'or* e?#lu#te! to 10 bec#u!e the !econd ) i! e?#lu#ted in #n en?iron*ent 6here it@! the n#*e o' # ?#ri#ble e!t#bli!hed by the LET 6ith the ?#lue 10:
1let#11)#0 33#)3
+acros
While !peci#l oper#tor! e.tend the !ynt#. o' Co**on i!p beyond 6h#t c#n be e.pre!!ed 6ith <u!t 'unction c#ll!, the !et o' !peci#l oper#tor! i! 'i.ed by the l#ngu#ge !t#nd#rd. 3#cro!, on the other h#nd, gi?e u!er! o' the l#ngu#ge # 6#y to e.tend it! !ynt#.. %! you !#6 in Ch#pter 3, # *#cro i! # 'unction th#t t#9e! !-e.pre!!ion! #! #rgu*ent! #nd return! # i!p 'or* th#t@! then e?#lu#ted in pl#ce o' the *#cro 'or*. &he e?#lu#tion o' # *#cro 'or* proceed! in t6o ph#!e!: /ir!t, the ele*ent! o' the *#cro
'or* #re p#!!ed, une?#lu#ted, to the *#cro 'unction. Second, the 'or* returned by the *#cro 'unction-c#lled it! e3pansion))i! e?#lu#ted #ccording to the nor*#l e?#lu#tion rule!. It@! i*port#nt to 9eep the t6o ph#!e! o' e?#lu#ting # *#cro 'or* cle#r in your *ind. It@! e#!y to lo!e tr#c9 6hen you@re typing e.pre!!ion! #t the $(P bec#u!e the t6o ph#!e! h#ppen one #'ter #nother #nd the ?#lue o' the !econd ph#!e i! i**edi#tely returned. 7ut 6hen i!p code i! co*piled, the t6o ph#!e! h#ppen #t co*pletely di''erent ti*e!, !o it@! i*port#nt to 9eep cle#r 6h#t@! h#ppening 6hen. /or in!t#nce, 6hen you co*pile # 6hole 'ile o' !ource code 6ith the 'unction COMPILE-FILE, #ll the *#cro 'or*! in the 'ile #re recur!i?ely e.p#nded until the code con!i!t! o' nothing but 'unction c#ll 'or*! #nd !peci#l 'or*!. &hi! *#crole!! code i! then co*piled into # /%S 'ile th#t the LOAD 'unction 9no6! ho6 to lo#d. &he co*piled code, ho6e?er, i!n@t e.ecuted until the 'ile i! lo#ded. 7ec#u!e *#cro! gener#te their e.p#n!ion #t co*pile ti*e, they c#n do rel#ti?ely l#rge #*ount! o' 6or9 gener#ting their e.p#n!ion 6ithout h#?ing to p#y 'or it 6hen the 'ile i! lo#ded or the 'unction! de'ined in the 'ile #re c#lled. Since the e?#lu#tor doe!n@t e?#lu#te the ele*ent! o' the *#cro 'or* be'ore p#!!ing the* to the *#cro 'unction, they don@t need to be 6ell-'or*ed i!p 'or*!. (#ch *#cro #!!ign! # *e#ning to the !e.pre!!ion! in the *#cro 'or* by ?irtue o' ho6 it u!e! the* to gener#te it! e.p#n!ion. In other 6ord!, e#ch *#cro de'ine! it! o6n loc#l !ynt#.. /or in!t#nce, the bac&wards *#cro 'ro* Ch#pter 3 de'ine! # !ynt#. in 6hich #n e.pre!!ion i! # leg#l bac&wards 'or* i' it@! # li!t th#t@! the re?er!e o' # leg#l i!p 'or*. I@ll t#l9 Fuite # bit *ore #bout *#cro! throughout thi! boo9. /or no6 the i*port#nt thing 'or you to re#liAe i! th#t *#cro!--6hile !ynt#ctic#lly !i*il#r to 'unction c#ll!--!er?e Fuite # di''erent purpo!e, pro?iding # hoo9 into the co*piler.10
I*ple*ent#tion! h#?e enough lee6#y th#t the e.pre!!ion 1e@#3#33 c#n leg#lly e?#lu#te to either true or '#l!e. 3ore to the point, 1e@#)#)3 c#n e?#lu#te to either true or '#l!e i' the ?#lue o' ) h#ppen! to be # nu*ber or ch#r#cter. &hu!, you !hould ne?er u!e EQ to co*p#re ?#lue! th#t *#y be nu*ber! or ch#r#cter!. It *#y !ee* to 6or9 in # predict#ble 6#y 'or cert#in ?#lue! in # p#rticul#r i*ple*ent#tion, but you h#?e no gu#r#ntee th#t it 6ill 6or9 the !#*e 6#y i' you !6itch i*ple*ent#tion!. %nd !6itching i*ple*ent#tion! *#y *e#n !i*ply upgr#ding your i*ple*ent#tion to # ne6 ?er!ion--i' your i!p i*ple*enter ch#nge! ho6 they repre!ent nu*ber! or ch#r#cter!, the beh#?ior o' EQ could ?ery 6ell ch#nge #! 6ell. &hu!, Co**on i!p de'ine! EQL to beh#?e li9e EQ e.cept th#t it #l!o i! gu#r#nteed to con!ider t6o ob<ect! o' the !#*e cl#!! repre!enting the !#*e nu*eric or ch#r#cter ?#lue to be eFui?#lent. &hu!, 1e@l#0#03 i! gu#r#nteed to be true. %nd 1e@l#0#0. 3 i! gu#r#nteed to be '#l!e !ince the integer ?#lue 1 #nd the 'lo#ting-point ?#lue #re in!t#nce! o' di''erent cl#!!e!. &here #re t6o !chool! o' thought #bout 6hen to u!e EQ #nd 6hen to u!e EQL: &he Hu!e EQ 6hen po!!ibleH c#*p #rgue! you !hould u!e EQ 6hen you 9no6 you #ren@t going to be co*-p#ring nu*ber! or ch#r#cter! bec#u!e B#C it@! # 6#y to indic#te th#t you #ren@t going to be co*p#ring nu*ber! or ch#r#cter! #nd BbC it 6ill be *#rgin#lly *ore e''icient !ince EQ doe!n@t h#?e to chec9 6hether it! #rgu*ent! #re nu*ber! or ch#r#cter!. &he H#l6#y! u!e EQLH c#*p !#y! you !hould ne?er u!e EQ bec#u!e B#C the potenti#l g#in in cl#rity i! lo!t bec#u!e e?ery ti*e !o*eone re#ding your code--including you--!ee! #n EQ, they h#?e to !top #nd chec9 6hether it@! being u!ed correctly Bin other 6ord!, th#t it@! ne?er going to be c#lled upon to co*p#re nu*ber! or ch#r#cter!C #nd BbC th#t the e''iciency di''erence bet6een EQ #nd EQL i! in the noi!e co*p#red to re#l per'or*#nce bottlenec9!. &he code in thi! boo9 i! 6ritten in the H#l6#y! u!e EQLH !tyle.1, &he other t6o eFu#lity predic#te!, EQUAL #nd EQUALP, #re gener#l in the !en!e th#t they c#n oper#te on #ll type! o' ob<ect!, but they@re *uch le!! 'und#*ent#l th#n EQ or EQL. &hey e#ch de'ine # !lightly le!! di!cri*in#ting notion o' eFui?#lence th#n EQL, #llo6ing di''erent ob<ect! to be con!idered eFui?#lent. &here@! nothing !peci#l #bout the p#rticul#r notion! o' eFui?#lence the!e 'unction! i*ple*ent e.cept th#t they@?e been 'ound to be h#ndy by i!p progr#**er! in the p#!t. I' the!e predic#te! don@t !uit your need!, you c#n #l6#y! de'ine your o6n predic#te 'unction th#t co*p#re! di''erent type! o' ob<ect! in the 6#y you need. EQUAL loo!en! the di!cri*in#tion o' EQL to con!ider li!t! eFui?#lent i' they h#?e the !#*e !tructure #nd content!, recur!i?ely, #ccording to EQUAL. EQUAL #l!o con!ider! !tring! eFui?#lent i' they cont#in the !#*e ch#r#cter!. It #l!o de'ine! # loo!er de'inition o' eFui?#lence th#n EQL 'or bit ?ector! #nd p#thn#*e!, t6o d#t# type! I@ll di!cu!! in 'uture ch#pter!. /or #ll other type!, it '#ll! b#c9 on EQL. EQUALP i! !i*il#r to EQUAL e.cept it@! e?en le!! di!cri*in#ting. It con!ider! t6o !tring! eFui?#lent i' they cont#in the !#*e ch#r#cter!, ignoring di''erence! in c#!e. It #l!o con!ider! t6o ch#r#cter! eFui?#lent i' they di''er only in c#!e. :u*ber! #re eFui?#lent under EQUALP i' they repre!ent the !#*e *#the*#tic#l ?#lue. &hu!, 1e@'alp#0#0. 3 i! true. i!t! 6ith EQUALP ele*ent! #re EQUALPG li9e6i!e, #rr#y! 6ith EQUALP ele*ent! #re EQUALP. %! 6ith EQUAL, there #re # 'e6 other d#t# type! th#t I h#?en@t co?ered yet 'or 6hich EQUALP c#n con!ider t6o ob<ect! eFui?#lent th#t neither EQL nor EQUAL 6ill. /or #ll other d#t# type!, EQUALP '#ll! b#c9 on EQL.
3#cro #nd !peci#l 'or*! th#t i*ple*ent control con!truct! #re typic#lly indented # little di''erently: the HbodyH ele*ent! #re indented t6o !p#ce! rel#ti?e to the opening p#renthe!i! o' the 'or*. &hu!:
1de('n#print-list#1list3 ##1dolist#1i#list3 ####1(ormat#t#4item:#7a764#i333
>o6e?er, you don@t need to 6orry too *uch #bout the!e rule! bec#u!e # proper i!p en?iron*ent !uch #! S I3( 6ill t#9e c#re o' it 'or you. In '#ct, one o' the #d?#nt#ge! o' i!p@! regul#r !ynt#. i! th#t it@! '#irly e#!y 'or !o't6#re !uch #! editor! to 9no6 ho6 to indent it. Since the indent#tion i! !uppo!ed to re'lect the !tructure o' the code #nd the !tructure i! *#r9ed by p#renthe!e!, it@! e#!y to let the editor indent your code 'or you. In S I3(, hitting &#b #t the beginning o' e#ch line 6ill c#u!e it to be indented #ppropri#tely, or you c#n re-indent # 6hole e.pre!!ion by po!itioning the cur!or on the opening p#renthe!i! #nd typing $-%@. 5r you c#n re-indent the 6hole body o' # 'unction 'ro* #ny6here 6ithin it by typing $-c#%-@. Indeed, e.perienced i!p progr#**er! tend to rely on their editor h#ndling indenting #uto*#tic#lly, not <u!t to *#9e their code loo9 nice but to detect typo!: once you get u!ed to ho6 code i! !uppo!ed to be indented, # *i!pl#ced p#renthe!i! 6ill be in!t#ntly recogniA#ble by the 6eird indent#tion your editor gi?e! you. /or e.#*ple, !uppo!e you 6ere 6riting # 'unction th#t 6#! !uppo!ed to loo9 li9e thi!:
1de('n#(oo#13 ##1i(#1test3 ####1do-one-thing3 ####1do-another-thing333
:o6 !uppo!e you #ccident#lly le't o'' the clo!ing p#renthe!i! #'ter test. 7ec#u!e you don@t bother counting p#renthe!e!, you Fuite li9ely 6ould h#?e #dded #n e.tr# p#renthe!i! #t the end o' the DEFUN 'or*, gi?ing you thi! code:
1de('n#(oo#13 ##1i(#1test ####1do-one-thing3 ####1do-another-thing3333
>o6e?er, i' you h#d been indenting by hitting &#b #t the beginning o' e#ch line, you 6ouldn@t h#?e code li9e th#t. In!te#d you@d h#?e thi!:
1de('n#(oo#13 ##1i(#1test #######1do-one-thing3 #######1do-another-thing3333
Seeing the then #nd el!e cl#u!e! indented 6#y out under the condition r#ther th#n <u!t indented !lightly rel#ti?e to the IF !ho6! you i**edi#tely th#t !o*ething i! #6ry. %nother i*port#nt 'or*#tting rule i! th#t clo!ing p#renthe!e! #re #l6#y! put on the !#*e line #! the l#!t ele*ent o' the li!t they@re clo!ing. &h#t i!, don@t 6rite thi!:
1de('n#(oo#13 ##1dotimes#1i#0 3 ####1(ormat#t#47d.#hello764#i3 ##3 3
&he !tring o' 333! #t the end *#y !ee* 'orbidding, but #! long your code i! properly indented the p#renthe!e! !hould '#de #6#y--no need to gi?e the* undue pro*inence by !pre#ding the* #cro!! !e?er#l line!. /in#lly, co**ent! !hould be pre'#ced 6ith one to 'our !e*icolon! depending on the !cope o' the co**ent #! 'ollo6!:
SSSS#Eo'r#semicolons#are#'sed#(or#a#(ile#header#comment. SSS#I#comment#with#three#semicolons#will#'s'all?#be#a#paragraph SSS#comment#that#applies#to#a#large#section#o(#code#that#(ollows5 1de('n#(oo#1)3 ##1dotimes#1i#)3 ####SS#Fwo#semicolons#indicate#this#comment#applies#to#the#code ####SS#that#(ollows.#8ote#that#this#comment#is#indented#the#same ####SS#as#the#code#that#(ollows. ####1some-('nction-call3 ####1another#i3##############S#this#comment#applies#to#this#line#onl? ####1and-another3############S#and#this#is#(or#this#line ####1ba*333
:o6 you@re re#dy to !t#rt loo9ing in gre#ter det#il #t the *#<or building bloc9! o' i!p progr#*!, 'unction!, ?#ri#ble!, #nd *#cro!. 8p ne.t: 'unction!.
1http://www-(ormal.stan(ord.ed'/jmc/histor?/lisp/node3.html 2
i!p i*ple*enter!, li9e i*ple*enter! o' #ny l#ngu#ge, h#?e *#ny 6#y! they c#n i*ple*ent #n e?#lu#tor, r#nging 'ro* # HpureH interpreter th#t interpret! the ob<ect! gi?en to the e?#lu#tor directly to # co*piler th#t tr#n!l#te! the ob<ect! into *#chine code th#t it then run!. In the *iddle #re i*ple*ent#tion! th#t co*pile the input into #n inter*edi#te 'or* !uch #! bytecode! 'or # ?irtu#l *#chine #nd then interpret! the bytecode!. 3o!t Co**on i!p i*ple*ent#tion! the!e d#y! u!e !o*e 'or* o' co*pil#tion e?en 6hen e?#lu#ting code #t run ti*e.
3So*eti*e!
the phr#!e s)e3pression re'er! to the te.tu#l repre!ent#tion #nd !o*eti*e! to the ob<ect! th#t re!ult 'ro* re#ding the te.tu#l repre!ent#tion. 8!u#lly either it@! cle#r 'ro* conte.t 6hich i! *e#nt or the di!tinction i!n@t th#t i*port#nt.
-:ot
#ll i!p ob<ect! c#n be 6ritten out in # 6#y th#t c#n be re#d b#c9 in. 7ut #nything you c#n READ c#n be printed b#c9 out Hre#d#blyH 6ith PRINT.
5&he 0In
e*pty li!t, 13, 6hich c#n #l!o be 6ritten NIL, i! both #n #to* #nd # li!t.
'#ct, #! you@ll !ee l#ter, n#*e! #ren@t intrin!ic#lly tied to #ny one 9ind o' thing. 4ou c#n u!e the !#*e n#*e, depending on conte.t, to re'er to both # ?#ri#ble #nd # 'unction, not to *ention !e?er#l other po!!ibilitie!.
2&he
c#!e-con?erting beh#?ior o' the re#der c#n, in '#ct, be cu!to*iAed, but under!t#nding 6hen #nd ho6 to ch#nge it reFuire! # *uch deeper di!cu!!ion o' the rel#tion bet6een n#*e!, !y*bol!, #nd other progr#* ele*ent! th#n I@* re#dy to get into <u!t yet.
,I@ll )5'
di!cu!! the rel#tion bet6een !y*bol! #nd p#c9#ge! in *ore det#il in Ch#pter 21.
cour!e, other le?el! o' correctne!! e.i!t in i!p, #! in other l#ngu#ge!. /or in!t#nce, the !e.pre!!ion th#t re!ult! 'ro* re#ding 1(oo#0#!3 i! !ynt#ctic#lly 6ell-'or*ed but c#n be e?#lu#ted only i' (oo i! the n#*e o' # 'unction or *#cro.
105ne 115ne 12In
other r#rely u!ed 9ind o' i!p 'or* i! # li!t 6ho!e 'ir!t ele*ent i! # lambda form. I@ll di!cu!! thi! 9ind o' 'or* in Ch#pter 5. other po!!ibility e.i!t!--it@! po!!ible to de'ine s0mbol macros th#t #re e?#lu#ted !lightly di''erently. We 6on@t 6orry #bout the*. Co**on i!p # !y*bol c#n n#*e both #n oper#tor--'unction, *#cro, or !peci#l oper#tor--#nd # ?#ri#ble. &hi! i! one o' the *#<or di''erence! bet6een Co**on i!p #nd Sche*e. &he di''erence i! !o*eti*e! de!cribed #! Co**on i!p being # i!p-2 ?!. Sche*e being # i!p-1--# i!p-2 h#! t6o n#*e!p#ce!, one 'or oper#tor! #nd one 'or ?#ri#ble!, but # i!p-1 u!e! # !ingle n#*e!p#ce. 7oth choice! h#?e #d?#nt#ge!, #nd p#rti!#n! c#n deb#te endle!!ly 6hich i! better.
13&he
other! pro?ide u!e'ul, but !o*e6h#t e!oteric, 'e#ture!. I@ll di!cu!! the* #! the 'e#ture! they !upport co*e up.
1-Well,
one di''erence e.i!t!--liter#l ob<ect! !uch #! Fuoted li!t!, but #l!o including double-Fuoted !tring!, liter#l #rr#y!, #nd ?ector! B6ho!e !ynt#. you@ll !ee l#terC, *u!t not be *odi'ied. Con!eFuently, #ny li!t! you pl#n to *#nipul#te you !hould cre#te 6ith LIST.
15&hi!
!ynt#. i! #n e.#*ple o' # reader macro. $e#der *#cro! *odi'y the !ynt#. the re#der u!e! to tr#n!l#te te.t into i!p ob<ect!. It i!, in '#ct, po!!ible to de'ine your o6n re#der *#cro!, but th#t@! # r#rely u!ed '#cility o' the l#ngu#ge. When *o!t i!per! t#l9 #bout He.tending the !ynt#.H o' the l#ngu#ge, they@re t#l9ing #bout regul#r *#cro!, #! I@ll di!cu!! in # *o*ent.
10People
6ithout e.perience u!ing i!p@! *#cro! or, 6or!e yet, be#ring the !c#r! o' C preproce!!orin'licted 6ound!, tend to get ner?ou! 6hen they re#liAe th#t *#cro c#ll! loo9 li9e regul#r 'unction c#ll!. &hi! turn! out not to be # proble* in pr#ctice 'or !e?er#l re#!on!. 5ne i! th#t *#cro 'or*! #re u!u#lly 'or*#tted di''erently th#n 'unction c#ll!. /or in!t#nce, you 6rite the 'ollo6ing:
1dolist#1)#(oo3 ##1print#)33
or
1dolist#1)#(oo3 #######1print#)33
the 6#y you 6ould i' DOLIST 6#! # 'unction. % good i!p en?iron*ent 6ill #uto*#tic#lly 'or*#t *#cro c#ll! correctly, e?en 'or u!er-de'ined *#cro!. %nd e?en i' # DOLIST 'or* 6#! 6ritten on # !ingle line, there #re !e?er#l clue! th#t it@! # *#cro: /or one, the e.pre!!ion 1)#(oo3 i! *e#ning'ul by it!el' only i' ) i! the n#*e o' # 'unction or *#cro. Co*bine th#t 6ith the l#ter occurrence o' ) #! # ?#ri#ble, #nd it@! pretty !ugge!ti?e th#t DOLIST i! # *#cro th#t@! cre#ting # binding 'or # ?#ri#ble n#*ed ). :#*ing con?ention! #l!o help--looping con!truct!, 6hich #re in?#ri#bly *#cro!--#re 'reFuently gi?en n#*e! !t#rting 6ith do.
128!ing
the e*pty li!t #! '#l!e i! # re'lection o' i!p@! herit#ge #! # li!t-proce!!ing l#ngu#ge *uch #! the u!e o' the integer 0 #! '#l!e in C i! # re'lection o' it! herit#ge #! # bit-t6iddling l#ngu#ge. :ot #ll i!p! h#ndle boole#n ?#lue! the !#*e 6#y. %nother o' the *#ny !ubtle di''erence! upon 6hich # good Co**on i!p ?!. Sche*e 'l#*e 6#r c#n r#ge 'or d#y! i! Sche*e@! u!e o' # di!tinct '#l!e ?#lue N(, 6hich i!n@t the !#*e ?#lue #! either the !y*bol nil or the e*pty li!t, 6hich #re #l!o di!tinct 'ro* e#ch other.
1,(?en
the l#ngu#ge !t#nd#rd i! # bit #*bi?#lent #bout 6hich o' EQ or EQL !hould be pre'erred. Object identit0 i! de'ined by EQ, but the !t#nd#rd de'ine! the phr#!e the same 6hen t#l9ing #bout ob<ect! to *e#n EQL unle!! #nother predic#te i! e.plicitly *entioned. &hu!, i' you 6#nt to be 100 percent technic#lly correct, you c#n !#y th#t 1-#3#!3 #nd 1-#4#33 e?#lu#te to Hthe !#*eH ob<ect but not th#t they e?#lu#te to Hidentic#lH ob<ect!. &hi! i!, #d*ittedly, # bit o' #n angels)on)pinheads 9ind o' i!!ue.
9. Functions
%'ter the rule! o' !ynt#. #nd !e*#ntic!, the three *o!t b#!ic co*ponent! o' #ll i!p progr#*! #re 'unction!, ?#ri#ble! #nd *#cro!. 4ou u!ed #ll three 6hile building the d#t#b#!e in Ch#pter 3, but I glo!!ed o?er # lot o' the det#il! o' ho6 they 6or9 #nd ho6 to be!t u!e the*. I@ll de?ote the ne.t 'e6 ch#pter! to the!e three topic!, !t#rting 6ith 'unction!, 6hich--li9e their counterp#rt! in other l#ngu#ge!--pro?ide the b#!ic *ech#ni!* 'or #b!tr#cting, 6ell, 'unction#lity.
&he bul9 o' i!p it!el' con!i!t! o' 'unction!. 3ore th#n three Fu#rter! o' the n#*e! de'ined in the l#ngu#ge !t#nd#rd n#*e 'unction!. %ll the built-in d#t# type! #re de'ined purely in ter*! o' 6h#t 'unction! oper#te on the*. (?en i!p@! po6er'ul ob<ect !y!te* i! built upon # conceptu#l e.ten!ion to 'unction!, generic 'unction!, 6hich I@ll co?er in Ch#pter 10. %nd, de!pite the i*port#nce o' *#cro! to &he i!p W#y, in the end #ll re#l 'unction#lity i! pro?ided by 'unction!. 3#cro! run #t co*pile ti*e, !o the code they gener#te--the code th#t 6ill #ctu#lly *#9e up the progr#* #'ter #ll the *#cro! #re e.p#nded--6ill con!i!t entirely o' c#ll! to 'unction! #nd !peci#l oper#tor!. :ot to *ention, *#cro! the*!el?e! #re #l!o 'unction!, #lbeit 'unction! th#t #re u!ed to gener#te code r#ther th#n to per'or* the #ction! o' the progr#*.1
%ny !y*bol c#n be u!ed #! # 'unction n#*e.2 8!u#lly 'unction n#*e! cont#in only #lph#betic ch#r#cter! #nd hyphen!, but other ch#r#cter! #re #llo6ed #nd #re u!ed in cert#in n#*ing con?ention!. /or in!t#nce, 'unction! th#t con?ert one 9ind o' ?#lue to #nother !o*eti*e! u!e -/ in the n#*e. /or e.#*ple, # 'unction to con?ert !tring! to 6idget! *ight be c#lled string-/widget. &he *o!t i*port#nt n#*ing con?ention i! the one *entioned in Ch#pter 2, 6hich i! th#t you con!truct co*pound n#*e! 6ith hyphen! r#ther th#n under!core! or inner c#p!. &hu!, (rob-widget i! better i!p !tyle th#n either (rob=widget or (robWidget. % 'unction@! p#r#*eter li!t de'ine! the ?#ri#ble! th#t 6ill be u!ed to hold the #rgu*ent! p#!!ed to the 'unction 6hen it@! c#lled.3 I' the 'unction t#9e! no #rgu*ent!, the li!t i! e*pty, 6ritten #! 13. +i''erent 'l#?or! o' p#r#*eter! h#ndle reFuired, option#l, *ultiple, #nd 9ey6ord #rgu*ent!. I@ll di!cu!! the det#il! in the ne.t !ection. I' # !tring liter#l 'ollo6! the p#r#*eter li!t, it@! # docu*ent#tion !tring th#t !hould de!cribe the purpo!e o' the 'unction. When the 'unction i! de'ined, the docu*ent#tion !tring 6ill be #!!oci#ted 6ith the n#*e o' the 'unction #nd c#n l#ter be obt#ined u!ing the DOCUMENTATION 'unction./in#lly, the body o' # DEFUN con!i!t! o' #ny nu*ber o' i!p e.pre!!ion!. &hey 6ill be e?#lu#ted in order 6hen the 'unction i! c#lled #nd the ?#lue o' the l#!t e.pre!!ion i! returned #! the ?#lue o' the 'unction. 5r the RETURN-FROM !peci#l oper#tor c#n be u!ed to return i**edi#tely 'ro* #ny6here in # 'unction, #! I@ll di!cu!! in # *o*ent. In Ch#pter 2 6e 6rote # hello-world 'unction, 6hich loo9ed li9e thi!:
1de('n#hello-world#13#1(ormat#t#4hello5#world433
4ou c#n no6 #n#lyAe the p#rt! o' thi! 'unction. It! n#*e i! hello-world, it! p#r#*eter li!t i! e*pty !o it t#9e! no #rgu*ent!, it h#! no docu*ent#tion !tring, #nd it! body con!i!t! o' one e.pre!!ion.
1(ormat#t#4hello5#world43
##1(ormat#t#4,'mming#7d#and#7d.764#)#?3 ##12#)#?33
&hi! 'unction i! n#*ed verbose-s'm, t#9e! t6o #rgu*ent! th#t 6ill be bound to the p#r#*eter! ) #nd ?, h#! # docu*ent#tion !tring, #nd h#! # body con!i!ting o' t6o e.pre!!ion!. &he ?#lue returned by the c#ll to + beco*e! the return ?#lue o' verbose-s'm.
7ptiona% "ara$eters
While *#ny 'unction!, li9e verbose-s'm, need only reFuired p#r#*eter!, not #ll 'unction! #re Fuite !o !i*ple. So*eti*e! # 'unction 6ill h#?e # p#r#*eter th#t only cert#in c#ller! 6ill c#re #bout, perh#p! bec#u!e there@! # re#!on#ble de'#ult ?#lue. %n e.#*ple i! # 'unction th#t cre#te! # d#t# !tructure th#t c#n gro6 #! needed. Since the d#t# !tructure c#n gro6, it doe!n@t *#tter--'ro* # correctne!! point o' ?ie6--6h#t the initi#l !iAe i!. 7ut c#ller! 6ho h#?e # good ide# ho6 *#ny ite*! they@re going to put into the d#t# !tructure *#y be #ble to i*pro?e per'or*#nce by !peci'ying # !peci'ic initi#l !iAe. 3o!t c#ller!, though, 6ould prob#bly r#ther let the code th#t i*ple*ent! the d#t# !tructure pic9 # good gener#l-purpo!e ?#lue. In Co**on i!p you c#n #cco**od#te both 9ind! o' c#ller! by u!ing #n option#l p#r#*eterG c#ller! 6ho don@t c#re 6ill get # re#!on#ble de'#ult, #nd other c#ller! c#n pro?ide # !peci'ic ?#lue.5 &o de'ine # 'unction 6ith option#l p#r#*eter!, #'ter the n#*e! o' #ny reFuired p#r#*eter!, pl#ce the !y*bol &o !"o#$% 'ollo6ed by the n#*e! o' the option#l p#r#*eter!. % !i*ple e.#*ple loo9! li9e thi!:
1de('n#(oo#1a#b#>optional#c#d3#1list#a#b#c#d33
When the 'unction i! c#lled, #rgu*ent! #re 'ir!t bound to the reFuired p#r#*eter!. %'ter #ll the reFuired p#r#*eter! h#?e been gi?en ?#lue!, i' there #re #ny #rgu*ent! le't, their ?#lue! #re #!!igned to the option#l p#r#*eter!. I' the #rgu*ent! run out be'ore the option#l p#r#*eter! do, the re*#ining option#l p#r#*eter! #re bound to the ?#lue NIL. &hu!, the 'unction de'ined pre?iou!ly gi?e! the 'ollo6ing re!ult!:
i!p 6ill !till chec9 th#t #n #ppropri#te nu*ber o' #rgu*ent! #re p#!!ed to the 'unction--in thi! c#!e bet6een t6o #nd 'our, inclu!i?e--#nd 6ill !ign#l #n error i' the 'unction i! c#lled 6ith too 'e6 or too *#ny. 5' cour!e, you@ll o'ten 6#nt # di''erent de'#ult ?#lue th#n NIL. 4ou c#n !peci'y the de'#ult ?#lue by repl#cing the p#r#*eter n#*e 6ith # li!t cont#ining # n#*e #nd #n e.pre!!ion. &he e.pre!!ion 6ill be e?#lu#ted only i' the c#ller doe!n@t p#!! enough #rgu*ent! to pro?ide # ?#lue 'or the option#l p#r#*eter. &he co**on c#!e i! !i*ply to pro?ide # ?#lue #! the e.pre!!ion.
1de('n#(oo#1a#>optional#1b#0 33#1list#a#b33
&hi! 'unction reFuire! one #rgu*ent th#t 6ill be bound to the p#r#*eter a. &he !econd p#r#*eter, b, 6ill t#9e either the ?#lue o' the !econd #rgu*ent, i' there i! one, or 10.
1(oo#0#!3#==/#10#!3 1(oo#03###==/#10#0 3
So*eti*e!, ho6e?er, you *#y need *ore 'le.ibility in choo!ing the de'#ult ?#lue. 4ou *#y 6#nt to co*pute # de'#ult ?#lue b#!ed on other p#r#*eter!. %nd you c#n--the de'#ult-?#lue e.pre!!ion c#n re'er to p#r#*eter! th#t occur e#rlier in the p#r#*eter li!t. I' you 6ere 6riting # 'unction th#t returned !o*e !ort o' repre!ent#tion o' # rect#ngle #nd you 6#nted to *#9e it e!peci#lly con?enient to *#9e !Fu#re!, you *ight u!e #n #rgu*ent li!t li9e thi!:
1de('n#ma&e-rectangle#1width#>optional#1height#width33#...3
6hich 6ould c#u!e the height p#r#*eter to t#9e the !#*e ?#lue #! the width p#r#*eter unle!! e.plicitly !peci'ied. 5cc#!ion#lly, it@! u!e'ul to 9no6 6hether the ?#lue o' #n option#l #rgu*ent 6#! !upplied by the c#ller or i! the de'#ult ?#lue. $#ther th#n 6riting code to chec9 6hether the ?#lue o' the p#r#*eter i! the de'#ult B6hich doe!n@t 6or9 #ny6#y, i' the c#ller h#ppen! to e.plicitly p#!! the de'#ult ?#lueC, you c#n #dd #nother ?#ri#ble n#*e to the p#r#*eter !peci'ier #'ter the de'#ult-?#lue e.pre!!ion. &hi! ?#ri#ble 6ill be bound to true i' the c#ller #ctu#lly !upplied #n #rgu*ent 'or thi! p#r#*eter #nd NIL other6i!e. 7y con?ention, the!e ?#ri#ble! #re u!u#lly n#*ed the !#*e #! the #ctu#l p#r#*eter 6ith # H-!upplied-pH on the end. /or e.#*ple:
1de('n#(oo#1a#b#>optional#1c#3#c-s'pplied-p33 ##1list#a#b#c#c-s'pplied-p33
Rest "ara$eters
5ption#l p#r#*eter! #re <u!t the thing 6hen you h#?e di!crete p#r#*eter! 'or 6hich the c#ller *#y or *#y not 6#nt to pro?ide ?#lue!. 7ut !o*e 'unction! need to t#9e # ?#ri#ble nu*ber o' #rgu*ent!.
Se?er#l o' the built-in 'unction! you@?e !een #lre#dy 6or9 thi! 6#y. FORMAT h#! t6o reFuired #rgu*ent!, the !tre#* #nd the control !tring. 7ut #'ter th#t it need! # ?#ri#ble nu*ber o' #rgu*ent! depending on ho6 *#ny ?#lue! need to be interpol#ted into the control !tring. &he + 'unction #l!o t#9e! # ?#ri#ble nu*ber o' #rgu*ent!--there@! no p#rticul#r re#!on to li*it it to !u**ing <u!t t6o nu*ber!G it 6ill !u* #ny nu*ber o' ?#lue!. BIt e?en 6or9! 6ith Aero #rgu*ent!, returning 0, the identity under #ddition.C &he 'ollo6ing #re #ll leg#l c#ll! o' tho!e t6o 'unction!:
1(ormat#t#4hello5#world43 1(ormat#t#4hello5#7a4#name3 1(ormat#t#4):#7d#?:#7d4#)#?3 123 12#03 12#0#!3 12#0#!#33
5b?iou!ly, you could 6rite 'unction! t#9ing # ?#ri#ble nu*ber o' #rgu*ent! by !i*ply gi?ing the* # lot o' option#l p#r#*eter!. 7ut th#t 6ould be incredibly p#in'ul--<u!t 6riting the p#r#*eter li!t 6ould be b#d enough, #nd th#t doe!n@t get into de#ling 6ith #ll the p#r#*eter! in the body o' the 'unction. &o do it properly, you@d h#?e to h#?e #! *#ny option#l p#r#*eter! #! the nu*ber o' #rgu*ent! th#t c#n leg#lly be p#!!ed in # 'unction c#ll. &hi! nu*ber i! i*ple*ent#tion dependent but gu#r#nteed to be #t le#!t 50. %nd in current i*ple*ent#tion! it r#nge! 'ro* -,0)0 to 530,,20,)11.0 7lech. &h#t 9ind o' *ind-bending tediu* i! de'initely not &he i!p W#y. In!te#d, i!p let! you include # c#tch#ll p#r#*eter #'ter the !y*bol &&'(!. I' # 'unction include! # &&'(! p#r#*eter, #ny #rgu*ent! re*#ining #'ter ?#lue! h#?e been doled out to #ll the reFuired #nd option#l p#r#*eter! #re g#thered up into # li!t th#t beco*e! the ?#lue o' the &&'(! p#r#*eter. &hu!, the p#r#*eter li!t! 'or FORMAT #nd + prob#bly loo9 !o*ething li9e thi!:
1de('n#(ormat#1stream#string#>rest#val'es3#...3 1de('n#2#1>rest#n'mbers3#...3#
;ey(ord "ara$eters
5ption#l #nd re!t p#r#*eter! gi?e you Fuite # bit o' 'le.ibility, but neither i! going to help you out *uch in the 'ollo6ing !itu#tion: Suppo!e you h#?e # 'unction th#t t#9e! 'our option#l p#r#*eter!. :o6 !uppo!e th#t *o!t o' the pl#ce! the 'unction i! c#lled, the c#ller 6#nt! to pro?ide # ?#lue 'or only one o' the 'our p#r#*eter! #nd, 'urther, th#t the c#ller! #re e?enly di?ided #! to 6hich p#r#*eter they 6ill u!e. &he c#ller! 6ho 6#nt to pro?ide # ?#lue 'or the 'ir!t p#r#*eter #re 'ine--they <u!t p#!! the one option#l #rgu*ent #nd le#?e o'' the re!t. 7ut #ll the other c#ller! h#?e to p#!! !o*e ?#lue 'or bet6een one #nd three #rgu*ent! they don@t c#re #bout. I!n@t th#t e.#ctly the proble* option#l p#r#*eter! 6ere de!igned to !ol?e" 5' cour!e it i!. &he proble* i! th#t option#l p#r#*eter! #re !till po!ition#l--i' the c#ller 6#nt! to p#!! #n e.plicit ?#lue 'or the 'ourth option#l p#r#*eter, it turn! the 'ir!t three option#l p#r#*eter! into reFuired p#r#*eter! 'or th#t c#ller. uc9ily, #nother p#r#*eter 'l#?or, 9ey6ord p#r#*eter!, #llo6 the c#ller to !peci'y 6hich ?#lue! go 6ith 6hich p#r#*eter!. &o gi?e # 'unction 9ey6ord p#r#*eter!, #'ter #ny reFuired, &o !"o#$%, #nd &&'(! p#r#*eter! you include the !y*bol &)'* #nd then #ny nu*ber o' 9ey6ord p#r#*eter !peci'ier!, 6hich 6or9 li9e option#l p#r#*eter !peci'ier!. >ere@! # 'unction th#t h#! only 9ey6ord p#r#*eter!:
1de('n#(oo#1>&e?#a#b#c3#1list#a#b#c33
When thi! 'unction i! c#lled, e#ch 9ey6ord p#r#*eter! i! bound to the ?#lue i**edi#tely 'ollo6ing # 9ey6ord o' the !#*e n#*e. $ec#ll 'ro* Ch#pter - th#t 9ey6ord! #re n#*e! th#t !t#rt 6ith # colon #nd th#t they@re #uto*#tic#lly de'ined #! !el'-e?#lu#ting con!t#nt!. I' # gi?en 9ey6ord doe!n@t #ppe#r in the #rgu*ent li!t, then the corre!ponding p#r#*eter i! #!!igned it! de'#ult ?#lue, <u!t li9e #n option#l p#r#*eter. 7ec#u!e the 9ey6ord #rgu*ent! #re l#beled, they c#n be p#!!ed in #ny order #! long #! they 'ollo6 #ny reFuired #rgu*ent!. /or in!t#nce, (oo c#n be in?o9ed #! 'ollo6!:
1(oo3################==/#189L#89L#89L3 1(oo#:a#03###########==/#10#89L#89L3 1(oo#:b#03###########==/#189L#0#89L3 1(oo#:c#03###########==/#189L#89L#03 1(oo#:a#0#:c#33######==/#10#89L#33 1(oo#:a#0#:b#!#:c#33#==/#10#!#33 1(oo#:a#0#:c#3#:b#!3#==/#10#!#33
%! 6ith option#l p#r#*eter!, 9ey6ord p#r#*eter! c#n pro?ide # de'#ult ?#lue 'or* #nd the n#*e o' # !upplied-p ?#ri#ble. In both 9ey6ord #nd option#l p#r#*eter!, the de'#ult ?#lue 'or* c#n re'er to p#r#*eter! th#t #ppe#r e#rlier in the p#r#*eter li!t.
1de('n#(oo#1>&e?#1a# 3#1b# #b-s'pplied-p3#1c#12#a#b333 ##1list#a#b#c#b-s'pplied-p33 1(oo#:a#03###########==/#10# #0#89L3 1(oo#:b#03###########==/#1 #0#0#F3 1(oo#:b#0#:c#43######==/#1 #0#4#F3 1(oo#:a#!#:b#0#:c#43#==/#1!#0#4#F3
%l!o, i' 'or !o*e re#!on you 6#nt the 9ey6ord the c#ller u!e! to !peci'y the p#r#*eter to be di''erent 'ro* the n#*e o' the #ctu#l p#r#*eter, you c#n repl#ce the p#r#*eter n#*e 6ith #nother li!t cont#ining the 9ey6ord to u!e 6hen c#lling the 'unction #nd the n#*e to be u!ed 'or the p#r#*eter. &he 'ollo6ing de'inition o' (oo:
1de('n#(oo#1>&e?#11:apple#a33#11:bo)#b3# 3#11:charlie#c3# #c-s'pplied-p33 ##1list#a#b#c#c-s'pplied-p33
&hi! !tyle i! *o!tly u!e'ul i' you 6#nt to co*pletely decouple the public %PI o' the 'unction 'ro* the intern#l det#il!, u!u#lly bec#u!e you 6#nt to u!e !hort ?#ri#ble n#*e! intern#lly but de!cripti?e 9ey6ord! in the %PI. It@! not, ho6e?er, ?ery 'reFuently u!ed.
Co*bining &o !"o#$% #nd &)'* p#r#*eter! yield! !urpri!ing enough re!ult! th#t you !hould prob#bly #?oid it #ltogether. &he proble* i! th#t i' # c#ller doe!n@t !upply ?#lue! 'or #ll the option#l p#r#*eter!, then tho!e p#r#*eter! 6ill e#t up the 9ey6ord! #nd ?#lue! intended 'or the 9ey6ord p#r#*eter!. /or in!t#nce, thi! 'unction un6i!ely *i.e! &o !"o#$% #nd &)'* p#r#*eter!:
1de('n#(oo#1)#>optional#?#>&e?#*3#1list#)#?#*33
&hi! i! bec#u!e the 9ey6ord :* i! t#9en #! # ?#lue to 'ill the option#l ? p#r#*eter, le#?ing only the #rgu*ent 3 to be proce!!ed. %t th#t point, i!p 6ill be e.pecting either # 9ey6ord;?#lue p#ir or nothing #nd 6ill co*pl#in. Perh#p! e?en 6or!e, i' the 'unction h#d h#d t6o &o !"o#$% p#r#*eter!, thi! l#!t c#ll 6ould h#?e re!ulted in the ?#lue! :* #nd 3 being bound to the t6o &o !"o#$% p#r#*eter! #nd the &)'* p#r#*eter * getting the de'#ult ?#lue NIL 6ith no indic#tion th#t #nything 6#! #*i!!. In gener#l, i' you 'ind your!el' 6riting # 'unction th#t u!e! both &o !"o#$% #nd &)'* p#r#*eter!, you !hould prob#bly <u!t ch#nge it to u!e #ll &)'* p#r#*eter!--they@re *ore 'le.ible, #nd you c#n #l6#y! #dd ne6 9ey6ord p#r#*eter! 6ithout di!turbing e.i!ting c#ller! o' the 'unction. 4ou c#n #l!o re*o?e 9ey6ord p#r#*eter!, #! long #! no one i! u!ing the*.2 In gener#l, u!ing 9ey6ord p#r#*eter! help! *#9e code *uch e#!ier to *#int#in #nd e?ol?e--i' you need to #dd !o*e ne6 beh#?ior to # 'unction th#t reFuire! ne6 p#r#*eter!, you c#n #dd 9ey6ord p#r#*eter! 6ithout h#?ing to touch, or e?en reco*pile, #ny e.i!ting code th#t c#ll! the 'unction. 4ou c#n !#'ely co*bine &&'(! #nd &)'* p#r#*eter!, but the beh#?ior *#y be # bit !urpri!ing initi#lly. :or*#lly the pre!ence o' either &&'(! or &)'* in # p#r#*eter li!t c#u!e! #ll the ?#lue! re*#ining #'ter the reFuired #nd &o !"o#$% p#r#*eter! h#?e been 'illed in to be proce!!ed in # p#rticul#r 6#y--either g#thered into # li!t 'or # &&'(! p#r#*eter or #!!igned to the #ppropri#te &)'* p#r#*eter! b#!ed on the 9ey6ord!. I' both &&'(! #nd &)'* #ppe#r in # p#r#*eter li!t, then both thing! h#ppen--#ll the re*#ining ?#lue!, 6hich include the 9ey6ord! the*!el?e!, #re g#thered into # li!t th#t@! bound to the &&'(! p#r#*eter, #nd the #ppropri#te ?#lue! #re #l!o bound to the &)'* p#r#*eter!. So, gi?en thi! 'unction:
1de('n#(oo#1>rest#rest#>&e?#a#b#c3#1list#rest#a#b#c33
>o6e?er, !o*eti*e! it@! con?enient to be #ble to return 'ro* the *iddle o' # 'unction !uch #! 6hen you 6#nt to bre#9 out o' ne!ted control con!truct!. In !uch c#!e! you c#n u!e the RETURN-FROM !peci#l oper#tor to i**edi#tely return #ny ?#lue 'ro* the 'unction. 4ou@ll !ee in Ch#pter 20 th#t RETURN-FROM i! #ctu#lly not tied to 'unction! #t #llG it@! u!ed to return 'ro* # bloc9 o' code de'ined 6ith the BLOC+ !peci#l oper#tor. >o6e?er, DEFUN #uto*#tic#lly 6r#p! the 6hole 'unction body in # bloc9 6ith the !#*e n#*e #! the 'unction. So, e?#lu#ting # RETURNFROM 6ith the n#*e o' the 'unction #nd the ?#lue you 6#nt to return 6ill c#u!e the 'unction to i**edi#tely e.it 6ith th#t ?#lue. RETURN-FROM i! # !peci#l oper#tor 6ho!e 'ir!t H#rgu*entH i! the n#*e o' the bloc9 'ro* 6hich to return. &hi! n#*e i!n@t e?#lu#ted #nd thu! i!n@t Fuoted. &he 'ollo6ing 'unction u!e! ne!ted loop! to 'ind the 'ir!t p#ir o' nu*ber!, e#ch le!! th#n 10, 6ho!e product i! gre#ter th#n the #rgu*ent, #nd it u!e! RETURN-FROM to return the p#ir #! !oon #! it 'ind! it:
1de('n#(oo#1n3 ##1dotimes#1i#0 3 ####1dotimes#1j#0 3 ######1when#1/#1U#i#j3#n3 ########1ret'rn-(rom#(oo#1list#i#j333333
%d*ittedly, h#?ing to !peci'y the n#*e o' the 'unction you@re returning 'ro* i! # bit o' # p#in--'or one thing, i' you ch#nge the 'unction@! n#*e, you@ll need to ch#nge the n#*e u!ed in the RETURN-FROM #! 6ell., 7ut it@! #l!o the c#!e th#t e.plicit RETURN-FROM! #re u!ed *uch le!! 'reFuently in i!p th#n ret'rn !t#te*ent! in C-deri?ed l#ngu#ge!, bec#u!e all i!p e.pre!!ion!, including control con!truct! !uch #! loop! #nd condition#l!, e?#lu#te to # ?#lue. So it@! not *uch o' # proble* in pr#ctice.
NO9nterpreted#E'nction#E;;/
In '#ct, you@?e #lre#dy u!ed FUNCTION, but it 6#! in di!gui!e. &he !ynt#. NC, 6hich you u!ed in Ch#pter 3, i! !ynt#ctic !ug#r 'or FUNCTION, <u!t the 6#y C i! !ynt#ctic !ug#r 'or QUOTE.11 &hu!, you c#n #l!o get the 'unction ob<ect 'or (oo li9e thi!:
$L-+,-./#NC(oo NO9nterpreted#E'nction#E;;/
5nce you@?e got the 'unction ob<ect, there@! re#lly only one thing you c#n do 6ith it--in?o9e it. Co**on i!p pro?ide! t6o 'unction! 'or in?o9ing # 'unction through # 'unction ob<ect: FUNCALL #nd APPLY.12 &hey di''er only in ho6 they obt#in the #rgu*ent! to p#!! to the 'unction. FUNCALL i! the one to u!e 6hen you 9no6 the nu*ber o' #rgu*ent! you@re going to p#!! to the 'unction #t the ti*e you 6rite the code. &he 'ir!t #rgu*ent to FUNCALL i! the 'unction ob<ect to be in?o9ed, #nd the re!t o' the #rgu*ent! #re p#!!ed onto th#t 'unction. &hu!, the 'ollo6ing t6o e.pre!!ion! #re eFui?#lent:
1(oo#0#!#33#===#1('ncall#NC(oo#0#!#33
>o6e?er, there@! little point in u!ing FUNCALL to c#ll # 'unction 6ho!e n#*e you 9no6 6hen you 6rite the code. In '#ct, the pre?iou! t6o e.pre!!ion! 6ill Fuite li9ely co*pile to e.#ctly the !#*e *#chine in!truction!. &he 'ollo6ing 'unction de*on!tr#te! # *ore #pt u!e o' FUNCALL. It #ccept! # 'unction ob<ect #! #n #rgu*ent #nd plot! # !i*ple %SCII-#rt hi!togr#* o' the ?#lue! returned by the #rgu*ent 'unction 6hen it@! in?o9ed on the ?#lue! 'ro* min to ma), !tepping by step.
1de('n#plot#1(n#min#ma)#step3 ##1loop#(or#i#(rom#min#to#ma)#b?#step#do ########1loop#repeat#1('ncall#(n#i3#do#1(ormat#t#4U433 ########1(ormat#t#4764333
&he FUNCALL e.pre!!ion co*pute! the ?#lue o' the 'unction 'or e#ch ?#lue o' i. &he inner LOOP u!e! th#t co*puted ?#lue to deter*ine ho6 *#ny ti*e! to print #n #!teri!9 to !t#nd#rd output. :ote th#t you don@t u!e FUNCTION or NC to get the 'unction ?#lue o' (nG you want it to be interpreted #! # ?#ri#ble bec#u!e it@! the ?#ri#ble@! ?#lue th#t 6ill be the 'unction ob<ect. 4ou c#n c#ll plot 6ith #ny 'unction th#t t#9e! # !ingle nu*eric #rgu*ent, !uch #! the built-in 'unction EXP th#t return! the ?#lue o' e r#i!ed to the po6er o' it! #rgu*ent.
$L-+,-./#1plot#NCe)p# #4#0/!3 U U UU UUUU UUUUUUU UUUUUUUUUUUU UUUUUUUUUUUUUUUUUUUU UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU 89L
FUNCALL, ho6e?er, doe!n@t do you #ny good 6hen the #rgu*ent li!t i! 9no6n only #t runti*e. /or in!t#nce, to !tic9 6ith the plot 'unction 'or #nother *o*ent, !uppo!e you@?e obt#ined # li!t
cont#ining # 'unction ob<ect, # *ini*u* #nd *#.i*u* ?#lue, #nd # !tep ?#lue. In other 6ord!, the li!t cont#in! the ?#lue! you 6#nt to p#!! #! #rgu*ent! to plot. Suppo!e thi! li!t i! in the ?#ri#ble plotdata. 4ou could in?o9e plot on the ?#lue! in th#t li!t li9e thi!:
1plot#1(irst#plot-data3#1second#plot-data3#1third#plot-data3#1(o'rth#plot-data33
&hi! 6or9! 'ine, but it@! pretty #nnoying to h#?e to e.plicitly unp#c9 the #rgu*ent! <u!t !o you c#n p#!! the* to plot. &h#t@! 6here APPLY co*e! in. i9e FUNCALL, the 'ir!t #rgu*ent to APPLY i! # 'unction ob<ect. 7ut #'ter the 'unction ob<ect, in!te#d o' indi?idu#l #rgu*ent!, it e.pect! # li!t. It then #pplie! the 'unction to the ?#lue! in the li!t. &hi! #llo6! you to 6rite the 'ollo6ing in!te#d:
1appl?#NCplot#plot-data3
%! # 'urther con?enience, APPLY c#n #l!o #ccept Hloo!eH #rgu*ent! #! long #! the l#!t #rgu*ent i! # li!t. &hu!, i' plot-data cont#ined <u!t the *in, *#., #nd !tep ?#lue!, you could !till u!e APPLY li9e thi! to plot the EXP 'unction o?er th#t r#nge:
1appl?#NCplot#NCe)p#plot-data3
APPLY doe!n@t c#re #bout 6hether the 'unction being #pplied t#9e! &o !"o#$%, &&'(!, or &)'* #rgu*ent!--the #rgu*ent li!t produced by co*bining #ny loo!e #rgu*ent! 6ith the 'in#l li!t *u!t be # leg#l #rgu*ent li!t 'or the 'unction 6ith enough #rgu*ent! 'or #ll the reFuired p#r#*eter! #nd only #ppropri#te 9ey6ord p#r#*eter!.
Anony$ous Functions
5nce you !t#rt 6riting, or e?en !i*ply u!ing, 'unction! th#t #ccept other 'unction! #! #rgu*ent!, you@re bound to di!co?er th#t !o*eti*e! it@! #nnoying to h#?e to de'ine #nd n#*e # 6hole !ep#r#te 'unction th#t@! u!ed in only one pl#ce, e!peci#lly 6hen you ne?er c#ll it by n#*e. When it !ee*! li9e o?er9ill to de'ine # ne6 'unction 6ith DEFUN, you c#n cre#te #n H#nony*ou!H 'unction u!ing # LAMBDA e.pre!!ion. %! di!cu!!ed in Ch#pter 3, # LAMBDA e.pre!!ion loo9! li9e thi!:
1lambda#1parameters3#body3
5ne 6#y to thin9 o' LAMBDA e.pre!!ion! i! #! # !peci#l 9ind o' 'unction n#*e 6here the n#*e it!el' directly de!cribe! 6h#t the 'unction doe!. &hi! e.pl#in! 6hy you c#n u!e # LAMBDA e.pre!!ion in the pl#ce o' # 'unction n#*e 6ith NC.
1('ncall#NC1lambda#1)#?3#12#)#?33#!#33#==/#"
4ou c#n e?en u!e # LAMBDA e.pre!!ion #! the Hn#*eH o' # 'unction in # 'unction c#ll e.pre!!ion. I' you 6#nted, you could 6rite the pre?iou! FUNCALL e.pre!!ion *ore conci!ely.
11lambda#1)#?3#12#)#?33#!#33#==/#"
7ut thi! i! #l*o!t ne?er doneG it@! *erely 6orth noting th#t it@! leg#l in order to e*ph#!iAe th#t LAMBDA e.pre!!ion! c#n be u!ed #ny6here # nor*#l 'unction n#*e c#n be.13 %nony*ou! 'unction! c#n be u!e'ul 6hen you need to p#!! # 'unction #! #n #rgu*ent to #nother 'unction #nd the 'unction you need to p#!! i! !i*ple enough to e.pre!! inline. /or in!t#nce, !uppo!e you 6#nted to plot the 'unction 53. 4ou could de'ine the 'ollo6ing 'unction:
1de('n#do'ble#1)3#1U#!#)33
&he other i*port#nt u!e o' LAMBDA e.pre!!ion! i! in *#9ing closures, 'unction! th#t c#pture p#rt o' the en?iron*ent 6here they@re cre#ted. 4ou u!ed clo!ure! # bit in Ch#pter 3, but the det#il! o' ho6 clo!ure! 6or9 #nd 6h#t they@re u!ed 'or i! re#lly *ore #bout ho6 ?#ri#ble! 6or9 th#n 'unction!, !o I@ll !#?e th#t di!cu!!ion 'or the ne.t ch#pter.
1+e!pite
the i*port#nce o' 'unction! in Co**on i!p, it i!n@t re#lly #ccur#te to de!cribe it #! # functional l#ngu#ge. It@! true !o*e o' Co**on i!p@! 'e#ture!, !uch #! it! li!t *#nipul#tion 'unction!, #re de!igned to be u!ed in # body-'or*S !tyle #nd th#t i!p h#! # pro*inent pl#ce in the hi!tory o' 'unction#l progr#**ing--3cC#rthy introduced *#ny ide#! th#t #re no6 con!idered i*port#nt in 'unction#l progr#**ing--but Co**on i!p 6#! intention#lly de!igned to !upport *#ny di''erent !tyle! o' progr#**ing. In the i!p '#*ily, Sche*e i! the ne#re!t thing to # HpureH 'unction#l l#ngu#ge, #nd e?en it h#! !e?er#l 'e#ture! th#t di!Fu#li'y it 'ro* #b!olute purity co*p#red to l#ngu#ge! !uch #! >#!9ell #nd 3 .
2Well,
#l*o!t #ny !y*bol. It@! unde'ined 6h#t h#ppen! i' you u!e #ny o' the n#*e! de'ined in the l#ngu#ge !t#nd#rd #! # n#*e 'or one o' your o6n 'unction!. >o6e?er, #! you@ll !ee in Ch#pter 21, the i!p p#c9#ge !y!te* #llo6! you to cre#te n#*e! in di''erent n#*e!p#ce!, !o thi! i!n@t re#lly #n i!!ue.
3P#r#*eter
li!t! #re !o*eti*e! #l!o c#lled lambda lists bec#u!e o' the hi!toric#l rel#tion!hip bet6een i!p@! notion o' 'unction! #nd the l#*bd# c#lculu!.
-/or
1doc'mentation#C(oo#C('nction3
return! the docu*ent#tion !tring 'or the 'unction (oo. :ote, ho6e?er, th#t docu*ent#tion !tring! #re intended 'or hu*#n con!u*ption, not progr#**#tic #cce!!. % i!p i*ple*ent#tion i!n@t re4uired to !tore the* #nd i! #llo6ed to di!c#rd the* #t #ny ti*e, !o port#ble progr#*! !houldn@t depend on their pre!ence. In !o*e i*ple*ent#tion! #n i*ple*ent#tion-de'ined ?#ri#ble need! to be !et be'ore it 6ill !tore docu*ent#tion !tring!.
5In
l#ngu#ge! th#t don@t !upport option#l p#r#*eter! directly, progr#**er! typic#lly 'ind 6#y! to !i*ul#te the*. 5ne techniFue i! to u!e di!tingui!hed Hno-?#lueH ?#lue! th#t the c#ller c#n p#!! to indic#te they 6#nt the de'#ult ?#lue o' # gi?en p#r#*eter. In C, 'or e.#*ple, it@! co**on to u!e 8+LL #! !uch # di!tingui!hed ?#lue. >o6e?er, !uch # protocol bet6een the 'unction #nd it! c#ller! i! #d hoc-in !o*e 'unction! or 'or !o*e #rgu*ent! 8+LL *#y be the di!tingui!hed ?#lue 6hile in other 'unction! or 'or other #rgu*ent! the *#gic ?#lue *#y be -1 or !o*e Nde(ined con!t#nt.
0&he
2/our
!t#nd#rd 'unction! t#9e both#&o !"o#$% #nd &)'* #rgu*ent!--READ-FROM-STRING, PARSE-NAMESTRING, WRITE-LINE, #nd WRITE-STRING. &hey 6ere le't th#t 6#y during !t#nd#rdiA#tion 'or b#c96#rd co*p#tibility 6ith e#rlier i!p di#lect!. READ-FROM-STRING tend! to be the one th#t c#tche! ne6 i!p progr#**er! *o!t 'reFuently--# c#ll !uch #! 1read-(romstring#s#:start#0 3 !ee*! to ignore the :start 9ey6ord #rgu*ent, re#ding 'ro* inde. 0 in!te#d o' 10. &h#t@! bec#u!e READ-FROM-STRING #l!o h#! t6o &o !"o#$% p#r#*eter! th#t !6#llo6ed up the #rgu*ent! :start #nd 10.
,%nother
*#cro, RETURN, doe!n@t reFuire # n#*e. >o6e?er, you c#n@t u!e it in!te#d o' RETURNFROM to #?oid h#?ing to !peci'y the 'unction n#*eG it@! !ynt#ctic !ug#r 'or returning 'ro* # bloc9 n#*ed NIL. I@ll co?er it, #long 6ith the det#il! o' BLOC+ #nd RETURN-FROM, in Ch#pter 20.
)
i!p, o' cour!e, i!n@t the only l#ngu#ge to tre#t 'unction! #! d#t#. C u!e! 'unction pointer!, Perl u!e! !ubroutine re'erence!, Python u!e! # !che*e !i*il#r to i!p, #nd CI introduce! deleg#te!, e!!enti#lly typed 'unction pointer!, #! #n i*pro?e*ent o?er D#?#@! r#ther clun9y re'lection #nd #nony*ou! cl#!! *ech#ni!*!.
10&he 11&he
e.#ct printed repre!ent#tion o' # 'unction ob<ect 6ill di''er 'ro* i*ple*ent#tion to i*ple*ent#tion. be!t 6#y to thin9 o' FUNCTION i! #! # !peci#l 9ind o' Fuot#tion.#QUOTEing # !y*bol pre?ent! it 'ro* being e?#lu#ted #t #ll, re!ulting in the !y*bol it!el' r#ther th#n the ?#lue o' the ?#ri#ble n#*ed by th#t !y*bol. FUNCTION #l!o circu*?ent! the nor*#l e?#lu#tion rule but, in!te#d o' pre?enting the !y*bol 'ro* being e?#lu#ted #t #ll, c#u!e! it to be e?#lu#ted #! the n#*e o' # 'unction, <u!t the 6#y it 6ould i' it 6ere u!ed #! the 'unction n#*e in # 'unction c#ll e.pre!!ion.
12&here@! 13In
#ctu#lly # third, the !peci#l oper#tor MULTIPLE-VALUE-CALL, but I@ll !#?e th#t 'or 6hen I di!cu!! e.pre!!ion! th#t return *ultiple ?#lue! in Ch#pter 20. Co**on i!p it@! #l!o po!!ible to u!e # LAMBDA e.pre!!ion #! #n #rgu*ent to FUNCALL Bor !o*e other 'unction th#t t#9e! # 'unction #rgu*ent !uch #! SORT or MAPCARC 6ith no NC be'ore it, li9e thi!:
1('ncall#1lambda#1)#?3#12#)#?33#!#33
&hi! i! leg#l #nd i! eFui?#lent to the ?er!ion 6ith the NC but 'or # tric9y re#!on. >i!toric#lly LAMBDA e.pre!!ion! by the*!el?e! 6eren@t e.pre!!ion! th#t could be e?#lu#ted. &h#t i! LAMBDA 6#!n@t the n#*e o' # 'unction, *#cro, or !peci#l oper#tor. $#ther, # li!t !t#rting 6ith the !y*bol LAMBDA 6#! # !peci#l !ynt#ctic con!truct th#t i!p recogniAed #! # 9ind o' 'unction n#*e. 7ut i' th#t 6ere !till true, then 1('ncall#1lambda#1...3#...33 6ould be illeg#l bec#u!e FUNCALL i! # 'unction #nd the nor*#l e?#lu#tion rule 'or # 'unction c#ll 6ould reFuire th#t the LAMBDA e.pre!!ion be e?#lu#ted. >o6e?er, l#te in the %:SI !t#nd#rdiA#tion proce!!, in order to *#9e it po!!ible to i*ple*ent IS ISP, #nother i!p di#lect being !t#nd#rdiAed #t the !#*e ti*e, !trictly #! # u!er-le?el co*p#tibility l#yer on top o' Co**on i!p, # LAMBDA *#cro 6#! de'ined th#t e.p#nd! into # c#ll to FUNCTION 6r#pped #round the LAMBDA e.pre!!ion. In other 6ord!, the 'ollo6ing LAMBDA e.pre!!ion:
1lambda#13#4!3
&hi! *#9e! it! u!e in # ?#lue po!ition, !uch #! #n #rgu*ent to FUNCALL, leg#l. In other 6ord!, it@! pure !ynt#ctic !ug#r. 3o!t 'ol9! either #l6#y! u!e NC be'ore LAMBDA e.pre!!ion! in ?#lue po!ition! or ne?er do. In thi! boo9, I #l6#y! u!e NC.
=. <aria2%es
&he ne.t b#!ic building bloc9 6e need to loo9 #t #re ?#ri#ble!. Co**on i!p !upport! t6o 9ind! o' ?#ri#ble!: le.ic#l #nd dyn#*ic.1 &he!e t6o type! corre!pond roughly to Hloc#lH #nd Hglob#lH ?#ri#ble! in other l#ngu#ge!. >o6e?er, the corre!pondence i! only #ppro.i*#te. 5n one h#nd, !o*e l#ngu#ge!@ Hloc#lH ?#ri#ble! #re in '#ct *uch li9e Co**on i!p@! dyn#*ic ?#ri#ble!.2 %nd on the other, !o*e l#ngu#ge!@ loc#l ?#ri#ble! #re le3icall0 scoped 6ithout pro?iding #ll the c#p#bilitie! pro?ided by Co**on i!p@! le.ic#l ?#ri#ble!. In p#rticul#r, not #ll l#ngu#ge! th#t pro?ide le.ic#lly !coped ?#ri#ble! !upport clo!ure!. &o *#9e *#tter! # bit *ore con'u!ing, *#ny o' the 'or*! th#t de#l 6ith ?#ri#ble! c#n be u!ed 6ith both
le.ic#l #nd dyn#*ic ?#ri#ble!. So I@ll !t#rt by di!cu!!ing # 'e6 #!pect! o' i!p@! ?#ri#ble! th#t #pply to both 9ind! #nd then co?er the !peci'ic ch#r#cteri!tic! o' le.ic#l #nd dyn#*ic ?#ri#ble!. &hen I@ll di!cu!! Co**on i!p@! gener#l-purpo!e #!!ign*ent oper#tor, SETF, 6hich i! u!ed to #!!ign ne6 ?#lue! to ?#ri#ble! #nd <u!t #bout e?ery other pl#ce th#t c#n hold # ?#lue.
<aria2%e Basics
%! in other l#ngu#ge!, in Co**on i!p ?#ri#ble! #re n#*ed pl#ce! th#t c#n hold # ?#lue. >o6e?er, in Co**on i!p, ?#ri#ble! #ren@t typed the 6#y they #re in l#ngu#ge! !uch #! D#?# or CEE. &h#t i!, you don@t need to decl#re the type o' ob<ect th#t e#ch ?#ri#ble c#n hold. In!te#d, # ?#ri#ble c#n hold ?#lue! o' #ny type #nd the ?#lue! c#rry type in'or*#tion th#t c#n be u!ed to chec9 type! #t runti*e. &hu!, Co**on i!p i! d0namicall0 t0ped--type error! #re detected dyn#*ic#lly. /or in!t#nce, i' you p#!! !o*ething other th#n # nu*ber to the + 'unction, Co**on i!p 6ill !ign#l # type error. 5n the other h#nd, Co**on i!p is # strongl0 t0ped l#ngu#ge in the !en!e th#t #ll type error! 6ill be detected-there@! no 6#y to tre#t #n ob<ect #! #n in!t#nce o' # cl#!! th#t it@! not.3 %ll ?#lue! in Co**on i!p #re, conceptu#lly #t le#!t, re'erence! to ob<ect!.- Con!eFuently, #!!igning # ?#ri#ble # ne6 ?#lue ch#nge! what ob<ect the ?#ri#ble re'er! to but h#! no e''ect on the pre?iou!ly re'erenced ob<ect. >o6e?er, i' # ?#ri#ble hold! # re'erence to # *ut#ble ob<ect, you c#n u!e th#t re'erence to *odi'y the ob<ect, #nd the *odi'ic#tion 6ill be ?i!ible to #ny code th#t h#! # re'erence to the !#*e ob<ect. 5ne 6#y to introduce ne6 ?#ri#ble! you@?e #lre#dy u!ed i! to de'ine 'unction p#r#*eter!. %! you !#6 in the pre?iou! ch#pter, 6hen you de'ine # 'unction 6ith DEFUN, the p#r#*eter li!t de'ine! the ?#ri#ble! th#t 6ill hold the 'unction@! #rgu*ent! 6hen it@! c#lled. /or e.#*ple, thi! 'unction de'ine! three ?#ri#ble!--), ?, #nd *--to hold it! #rgu*ent!.
1de('n#(oo#1)#?#*3#12#)#?#*33
(#ch ti*e # 'unction i! c#lled, i!p cre#te! ne6 bindings to hold the #rgu*ent! p#!!ed by the 'unction@! c#ller. % binding i! the runti*e *#ni'e!t#tion o' # ?#ri#ble. % !ingle ?#ri#ble--the thing you c#n point to in the progr#*@! !ource code--c#n h#?e *#ny di''erent binding! during # run o' the progr#*. % !ingle ?#ri#ble c#n e?en h#?e *ultiple binding! #t the !#*e ti*eG p#r#*eter! to # recur!i?e 'unction, 'or e.#*ple, #re rebound 'or e#ch c#ll to the 'unction. %! 6ith #ll Co**on i!p ?#ri#ble!, 'unction p#r#*eter! hold ob<ect re'erence!.5 &hu!, you c#n #!!ign # ne6 ?#lue to # 'unction p#r#*eter 6ithin the body o' the 'unction, #nd it 6ill not #''ect the binding! cre#ted 'or #nother c#ll to the !#*e 'unction. 7ut i' the ob<ect p#!!ed to # 'unction i! *ut#ble #nd you ch#nge it in the 'unction, the ch#nge! 6ill be ?i!ible to the c#ller !ince both the c#ller #nd the c#llee 6ill be re'erencing the !#*e ob<ect. %nother 'or* th#t introduce! ne6 ?#ri#ble! i! the LET !peci#l oper#tor. &he !9eleton o' # LET 'or* loo9! li9e thi!:
1let#1variableU3 ##body-formU3
6here e#ch variable i! # ?#ri#ble initi#liA#tion 'or*. (#ch initi#liA#tion 'or* i! either # li!t cont#ining # ?#ri#ble n#*e #nd #n initi#l ?#lue 'or* or--#! # !horth#nd 'or initi#liAing the ?#ri#ble to NIL--# pl#in ?#ri#ble n#*e. &he 'ollo6ing LET 'or*, 'or e.#*ple, bind! the three ?#ri#ble! ), ?, #nd * 6ith initi#l ?#lue! 10, 20, #nd NIL:
1let#11)#0 3#1?#! 3#*3
##...3
When the LET 'or* i! e?#lu#ted, #ll the initi#l ?#lue 'or*! #re 'ir!t e?#lu#ted. &hen ne6 binding! #re cre#ted #nd initi#liAed to the #ppropri#te initi#l ?#lue! be'ore the body 'or*! #re e.ecuted. Within the body o' the LET, the ?#ri#ble n#*e! re'er to the ne6ly cre#ted binding!. %'ter the LET, the n#*e! re'er to 6h#te?er, i' #nything, they re'erred to be'ore the LET. &he ?#lue o' the l#!t e.pre!!ion in the body i! returned #! the ?#lue o' the LET e.pre!!ion. i9e 'unction p#r#*eter!, ?#ri#ble! introduced 6ith LET #re rebound e#ch ti*e the LET i! entered.0 &he scope o' 'unction p#r#*eter! #nd LET ?#ri#ble!--the #re# o' the progr#* 6here the ?#ri#ble n#*e c#n be u!ed to re'er to the ?#ri#ble@! binding--i! deli*ited by the 'or* th#t introduce! the ?#ri#ble. &hi! 'or*--the 'unction de'inition or the LET--i! c#lled the binding form. %! you@ll !ee in # bit, the t6o type! o' ?#ri#ble!--le.ic#l #nd dyn#*ic--u!e t6o !lightly di''erent !coping *ech#ni!*!, but in both c#!e! the !cope i! deli*ited by the binding 'or*. I' you ne!t binding 'or*! th#t introduce ?#ri#ble! 6ith the !#*e n#*e, then the binding! o' the inner*o!t ?#ri#ble shadows the outer binding!. /or in!t#nce, 6hen the 'ollo6ing 'unction i! c#lled, # binding i! cre#ted 'or the p#r#*eter ) to hold the 'unction@! #rgu*ent. &hen the 'ir!t LET cre#te! # ne6 binding 6ith the initi#l ?#lue 2, #nd the inner LET cre#te! yet #nother binding, thi! one 6ith the initi#l ?#lue 3. &he b#r! on the right *#r9 the !cope o' e#ch binding.
1de('n#(oo#1)3 ##1(ormat#t#4Tarameter:#7a764#)3######S#XO------#)#is#arg'ment# ##1let#11)#!33########################S#X ####1(ormat#t#4;'ter#L-F:#7a764#)3####S#X#XO----#)#is#! ####1let#11)#333######################S#X#X ######1(ormat#t#49nner#L-F:#7a764#)33#S#X#X#XO--#)#is#3 ####1(ormat#t#4;'ter#L-F:#7a764#)33###S#X#X ##1(ormat#t#4Tarameter:#7a764#)33#####S#X
(#ch re'erence to ) 6ill re'er to the binding 6ith the !*#lle!t enclo!ing !cope. 5nce control le#?e! the !cope o' one binding 'or*, the binding 'ro* the i**edi#tely enclo!ing !cope i! un!h#do6ed #nd ) re'er! to it in!te#d. &hu!, c#lling (oo re!ult! in thi! output:
$L-+,-./#1(oo#03 Tarameter:#0 ;'ter#L-F:#! 9nner#L-F:#3 ;'ter#L-F:#! Tarameter:#0 89L
In 'uture ch#pter! I@ll di!cu!! other con!truct! th#t #l!o !er?e #! binding 'or*!--#ny con!truct th#t introduce! # ne6 ?#ri#ble n#*e th#t@! u!#ble only 6ithin the con!truct i! # binding 'or*. /or in!t#nce, in Ch#pter 2 you@ll *eet the DOTIMES loop, # b#!ic counting loop. It introduce! # ?#ri#ble th#t hold! the ?#lue o' # counter th#t@! incre*ented e#ch ti*e through the loop. &he 'ollo6ing loop, 'or e.#*ple, 6hich print! the nu*ber! 'ro* 0 to ), bind! the ?#ri#ble ):
1dotimes#1)#0 3#1(ormat#t#47d#4#)33
%nother binding 'or* i! # ?#ri#nt o' LET, LET*. &he di''erence i! th#t in # LET, the ?#ri#ble n#*e! c#n be u!ed only in the body o' the LET--the p#rt o' the LET #'ter the ?#ri#ble! li!t--but in # LET*, the initi#l ?#lue 'or*! 'or e#ch ?#ri#ble c#n re'er to ?#ri#ble! introduced e#rlier in the ?#ri#ble! li!t. &hu!,
>o6e?er, you could #chie?e the !#*e re!ult 6ith ne!ted LET!.
1let#11)#0 33 ##1let#11?#12#)#0 333 ####1list#)#?333
the re'erence to co'nt in!ide the LAMBDA 'or* !hould be leg#l #ccording to the rule! o' le.ic#l !coping. 4et the #nony*ou! 'unction cont#ining the re'erence 6ill be returned #! the ?#lue o' the LET 'or* #nd c#n be in?o9ed, ?i# FUNCALL, by code th#t@! not in the !cope o' the LET. So 6h#t h#ppen!" %! it turn! out, 6hen co'nt i! # le.ic#l ?#ri#ble, it <u!t 6or9!. &he binding o' co'nt cre#ted 6hen the 'lo6 o' control entered the LET 'or* 6ill !tic9 #round 'or #! long #! needed, in thi! c#!e 'or #! long #! !o*eone hold! onto # re'erence to the 'unction ob<ect returned by the LET 'or*. &he #nony*ou! 'unction i! c#lled # closure bec#u!e it Hclo!e! o?erH the binding cre#ted by the LET. &he 9ey thing to under!t#nd #bout clo!ure! i! th#t it@! the binding, not the ?#lue o' the ?#ri#ble, th#t@! c#ptured. &hu!, # clo!ure c#n not only #cce!! the ?#lue o' the ?#ri#ble! it clo!e! o?er but c#n #l!o #!!ign ne6 ?#lue! th#t 6ill per!i!t bet6een c#ll! to the clo!ure. /or in!t#nce, you c#n c#pture the clo!ure cre#ted by the pre?iou! e.pre!!ion in # glob#l ?#ri#ble li9e thi!:
1de(parameter#U(nU#1let#11co'nt# 33#NC1lambda#13#1set(#co'nt#102#co'nt33333
&hen e#ch ti*e you in?o9e it, the ?#lue o' count 6ill incre#!e by one.
$L-+,-./#1('ncall#U(nU3 0 $L-+,-./#1('ncall#U(nU3
! $L-+,-./#1('ncall#U(nU3 3
% !ingle clo!ure c#n clo!e o?er *#ny ?#ri#ble binding! !i*ply by re'erring to the*. 5r *ultiple clo!ure! c#n c#pture the !#*e binding. /or in!t#nce, the 'ollo6ing e.pre!!ion return! # li!t o' three clo!ure!, one th#t incre*ent! the ?#lue o' the clo!ed o?er co'nt binding, one th#t decre*ent! it, #nd one th#t return! the current ?#lue:
1let#11co'nt# 33 ##1list ###NC1lambda#13#1inc(#co'nt33 ###NC1lambda#13#1dec(#co'nt33 ###NC1lambda#13#co'nt333
&he di''erence bet6een the t6o 'or*! i! th#t DEFPARAMETER #l6#y! #!!ign! the initi#l ?#lue to the n#*ed ?#ri#ble 6hile DEFVAR doe! !o only i' the ?#ri#ble i! unde'ined. % DEFVAR 'or* c#n #l!o be u!ed 6ith no initi#l ?#lue to de'ine # glob#l ?#ri#ble 6ithout gi?ing it # ?#lue. Such # ?#ri#ble i! !#id to be unbound. Pr#ctic#lly !pe#9ing, you !hould u!e DEFVAR to de'ine ?#ri#ble! th#t 6ill cont#in d#t# you@d 6#nt to 9eep e?en i' you *#de # ch#nge to the !ource code th#t u!e! the ?#ri#ble. /or in!t#nce, !uppo!e the t6o ?#ri#ble! de'ined pre?iou!ly #re p#rt o' #n #pplic#tion 'or controlling # 6idget '#ctory. It@! #ppropri#te to de'ine the Uco'ntU ?#ri#ble 6ith DEFVAR bec#u!e the nu*ber o' 6idget! *#de !o '#r i!n@t in?#lid#ted <u!t bec#u!e you *#9e !o*e ch#nge! to the 6idget-*#9ing code., 5n the other h#nd, the ?#ri#ble Ugap-toleranceU pre!u*#bly h#! !o*e e''ect on the beh#?ior o' the 6idget-*#9ing code it!el'. I' you decide you need # tighter or loo!er toler#nce #nd ch#nge the ?#lue in the DEFPARAMETER 'or*, you@d li9e the ch#nge to t#9e e''ect 6hen you reco*pile #nd relo#d the
'ile. %'ter de'ining # ?#ri#ble 6ith DEFVAR or DEFPARAMETER, you c#n re'er to it 'ro* #ny6here. /or in!t#nce, you *ight de'ine thi! 'unction to incre*ent the count o' 6idget! *#de:
1de('n#increment-widget-co'nt#13#1inc(#Uco'ntU33
&he #d?#nt#ge o' glob#l ?#ri#ble! i! th#t you don@t h#?e to p#!! the* #round. 3o!t l#ngu#ge! !tore the !t#nd#rd input #nd output !tre#*! in glob#l ?#ri#ble! 'or e.#ctly thi! re#!on--you ne?er 9no6 6hen you@re going to 6#nt to print !o*ething to !t#nd#rd out, #nd you don@t 6#nt e?ery 'unction to h#?e to #ccept #nd p#!! on #rgu*ent! cont#ining tho!e !tre#*! <u!t in c#!e !o*eone 'urther do6n the line need! the*. >o6e?er, once # ?#lue, !uch #! the !t#nd#rd output !tre#*, i! !tored in # glob#l ?#ri#ble #nd you h#?e 6ritten code th#t re'erence! th#t glob#l ?#ri#ble, it@! te*pting to try to te*por#rily *odi'y the beh#?ior o' th#t code by ch#nging the ?#ri#ble@! ?#lue. /or in!t#nce, !uppo!e you@re 6or9ing on # progr#* th#t cont#in! !o*e lo6-le?el logging 'unction! th#t print to the !tre#* in the glob#l ?#ri#ble Ustandard-o'tp'tU. :o6 !uppo!e th#t in p#rt o' the progr#* you 6#nt to c#pture #ll the output gener#ted by tho!e 'unction! into # 'ile. 4ou *ight open # 'ile #nd #!!ign the re!ulting !tre#* to Ustandard-o'tp'tU. :o6 the lo6-le?el 'unction! 6ill !end their output to the 'ile. &hi! 6or9! 'ine until you 'orget to !et Ustandard-o'tp'tU b#c9 to the origin#l !tre#* 6hen you@re done. I' you 'orget to re!et Ustandard-o'tp'tU, #ll the other code in the progr#* th#t u!e! Ustandard-o'tp'tU 6ill #l!o !end it! output to the 'ile.) Wh#t you re#lly 6#nt, it !ee*!, i! # 6#y to 6r#p # piece o' code in !o*ething th#t !#y!, H%ll code belo6 here--#ll the 'unction! it c#ll!, #ll the 'unction! they c#ll, #nd !o on, do6n to the lo6e!t-le?el 'unction!--!hould u!e this ?#lue 'or the glob#l ?#ri#ble Ustandard-o'tp'tU.H &hen 6hen the highle?el 'unction return!, the old ?#lue o' Ustandard-o'tp'tU !hould be #uto*#tic#lly re!tored. It turn! out th#t th#t@! e.#ctly 6h#t Co**on i!p@! other 9ind o' ?#ri#ble--dyn#*ic ?#ri#ble!--let you do. When you bind # dyn#*ic ?#ri#ble--'or e.#*ple, 6ith # LET ?#ri#ble or # 'unction p#r#*eter--the binding th#t@! cre#ted on entry to the binding 'or* repl#ce! the glob#l binding 'or the dur#tion o' the binding 'or*. 8nli9e # le.ic#l binding, 6hich c#n be re'erenced by code only 6ithin the le.ic#l !cope o' the binding 'or*, # dyn#*ic binding c#n be re'erenced by #ny code th#t@! in?o9ed during the e.ecution o' the binding 'or*.10 %nd it turn! out th#t #ll glob#l ?#ri#ble! #re, in '#ct, dyn#*ic ?#ri#ble!. &hu!, i' you 6#nt to te*por#rily rede'ine Ustandard-o'tp'tU, the 6#y to do it i! !i*ply to rebind it, !#y, 6ith # LET.
1let#11Ustandard-o'tp'tU#Usome-other-streamU33 ##1st'((33
In #ny code th#t run! #! # re!ult o' the c#ll to st'((, re'erence! to Ustandard-o'tp'tU 6ill u!e the binding e!t#bli!hed by the LET. %nd 6hen st'(( return! #nd control le#?e! the LET, the ne6 binding o' Ustandard-o'tp'tU 6ill go #6#y #nd !ub!eFuent re'erence! to Ustandardo'tp'tU 6ill !ee the binding th#t 6#! current be'ore the LET. %t #ny gi?en ti*e, the *o!t recently e!t#bli!hed binding !h#do6! #ll other binding!. Conceptu#lly, e#ch ne6 binding 'or # gi?en dyn#*ic ?#ri#ble i! pu!hed onto # !t#c9 o' binding! 'or th#t ?#ri#ble, #nd re'erence! to the ?#ri#ble #l6#y! u!e the *o!t recent binding. %! binding 'or*! return, the binding! they cre#ted #re popped o'' the !t#c9, e.po!ing pre?iou! binding!.11
&he DEFVAR cre#te! # glob#l binding 'or the ?#ri#ble U)U 6ith the ?#lue 10. &he re'erence to U)U in (oo 6ill loo9 up the current binding dyn#*ic#lly. I' you c#ll (oo 'ro* the top le?el, the glob#l binding cre#ted by the DEFVAR i! the only binding #?#il#ble, !o it print! 10.
$L-+,-./#1(oo3 [:#0 89L
7ut you c#n u!e LET to cre#te # ne6 binding th#t te*por#rily !h#do6! the glob#l binding, #nd (oo 6ill print # di''erent ?#lue.
$L-+,-./#1let#11U)U#! 33#1(oo33 [:#! 89L
:o6 c#ll (oo #g#in, 6ith no LET, #nd it #g#in !ee! the glob#l binding.
$L-+,-./#1(oo3 [:#0 89L
:ote th#t the *iddle c#ll to (oo i! 6r#pped in # LET th#t bind! U)U to the ne6 ?#lue 20. When you run bar, you get thi! re!ult:
$L-+,-./#1bar3 [:#0 [:#! [:#0 89L
%! you c#n !ee, the 'ir!t c#ll to (oo !ee! the glob#l binding, 6ith it! ?#lue o' 10. &he *iddle c#ll, ho6e?er, !ee! the ne6 binding, 6ith the ?#lue 20. 7ut #'ter the LET, (oo once #g#in !ee! the glob#l binding. %! 6ith le.ic#l binding!, #!!igning # ne6 ?#lue #''ect! only the current binding. &o !ee thi!, you c#n rede'ine (oo to include #n #!!ign*ent to U)U.
1de('n#(oo#13 ##1(ormat#t#4Le(ore#assignment70Rt[:#7d764#U)U3 ##1set(#U)U#12#0#U)U33 ##1(ormat#t#4I(ter#assignment70Rt[:#7d764#U)U33
:o6 (oo print! the ?#lue o' U)U, incre*ent! it, #nd print! it #g#in. I' you <u!t run (oo, you@ll !ee thi!:
$L-+,-./#1(oo3
:otice th#t U)U !t#rted #t 11--the e#rlier c#ll to (oo re#lly did ch#nge the glob#l ?#lue. &he 'ir!t c#ll to (oo 'ro* bar incre*ent! the glob#l binding to 12. &he *iddle c#ll doe!n@t !ee the glob#l binding bec#u!e o' the LET. &hen the l#!t c#ll c#n !ee the glob#l binding #g#in #nd incre*ent! it 'ro* 12 to 13. So ho6 doe! thi! 6or9" >o6 doe! LET 9no6 th#t 6hen it bind! U)U it@! !uppo!ed to cre#te # dyn#*ic binding r#ther th#n # nor*#l le.ic#l binding" It 9no6! bec#u!e the n#*e h#! been decl#red special.12 &he n#*e o' e?ery ?#ri#ble de'ined 6ith DEFVAR #nd DEFPARAMETER i! #uto*#tic#lly decl#red glob#lly !peci#l. &hi! *e#n! 6hene?er you u!e !uch # n#*e in # binding 'or*--in # LET or #! # 'unction p#r#*eter or #ny other con!truct th#t cre#te! # ne6 ?#ri#ble binding--the binding th#t@! cre#ted 6ill be # dyn#*ic binding. &hi! i! 6hy the UnamingU UconventionU i! !o i*port#nt--it@d be b#d ne6! i' you u!ed # n#*e 'or 6h#t you thought 6#! # le.ic#l ?#ri#ble #nd th#t ?#ri#ble h#ppened to be glob#lly !peci#l. 5n the one h#nd, code you c#ll could ch#nge the ?#lue o' the binding out 'ro* under youG on the other, you *ight be !h#do6ing # binding e!t#bli!hed by code higher up on the !t#c9. I' you #l6#y! n#*e glob#l ?#ri#ble! #ccording to the U n#*ing con?ention, you@ll ne?er #ccident#lly u!e # dyn#*ic binding 6here you intend to e!t#bli!h # le.ic#l binding. It@! #l!o po!!ible to decl#re # n#*e loc#lly !peci#l. I', in # binding 'or*, you decl#re # n#*e !peci#l, then the binding cre#ted 'or th#t ?#ri#ble 6ill be dyn#*ic r#ther th#n le.ic#l. 5ther code c#n loc#lly decl#re # n#*e !peci#l in order to re'er to the dyn#*ic binding. >o6e?er, loc#lly !peci#l ?#ri#ble! #re rel#ti?ely r#re, !o you needn@t 6orry #bout the*.13 +yn#*ic binding! *#9e glob#l ?#ri#ble! *uch *ore *#n#ge#ble, but it@! i*port#nt to notice they !till #llo6 #ction #t # di!t#nce. 7inding # glob#l ?#ri#ble h#! t6o #t # di!t#nce e''ect!--it c#n ch#nge the beh#?ior o' do6n!tre#* code, #nd it #l!o open! the po!!ibility th#t do6n!tre#* code 6ill #!!ign # ne6 ?#lue to # binding e!t#bli!hed higher up on the !t#c9. 4ou !hould u!e dyn#*ic ?#ri#ble! only 6hen you need to t#9e #d?#nt#ge o' one or both o' the!e ch#r#cteri!tic!.
#onstants
5ne other 9ind o' ?#ri#ble I h#?en@t *entioned #t #ll i! the o.y*oronic Hcon!t#nt ?#ri#ble.H %ll con!t#nt! #re glob#l #nd #re de'ined 6ith DEFCONSTANT. &he b#!ic 'or* o' DEFCONSTANT i! li9e DEFPARAMETER.
1de(constant#name#initial-value-form#D#documentation-string#G3
%! 6ith DEFVAR #nd DEFPARAMETER, DEFCONSTANT h#! # glob#l e''ect on the n#*e u!ed-there#'ter the n#*e c#n be u!ed only to re'er to the con!t#ntG it c#n@t be u!ed #! # 'unction p#r#*eter or rebound 6ith #ny other binding 'or*. &hu!, *#ny i!p progr#**er! 'ollo6 # n#*ing con?ention o'
u!ing n#*e! !t#rting #nd ending 6ith 2 'or con!t#nt!. &hi! con?ention i! !o*e6h#t le!! uni?er!#lly 'ollo6ed th#n the U-n#*ing con?ention 'or glob#lly !peci#l n#*e! but i! # good ide# 'or the !#*e re#!on.1%nother thing to note #bout DEFCONSTANT i! th#t 6hile the l#ngu#ge #llo6! you to rede'ine # con!t#nt by ree?#lu#ting # DEFCONSTANT 6ith # di''erent initi#l-?#lue-'or*, 6h#t e.#ctly h#ppen! #'ter the rede'inition i!n@t de'ined. In pr#ctice, *o!t i*ple*ent#tion! 6ill reFuire you to ree?#lu#te #ny code th#t re'er! to the con!t#nt in order to !ee the ne6 ?#lue !ince the old ?#lue *#y 6ell h#?e been inlined. Con!eFuently, it@! # good ide# to u!e DEFCONSTANT only to de'ine thing! th#t #re reall0 con!t#nt, !uch #! the ?#lue o' :I . /or thing! you *ight e?er 6#nt to ch#nge, you !hould u!e DEFPARAMETER in!te#d.
Assign$ent
5nce you@?e cre#ted # binding, you c#n do t6o thing! 6ith it: get the current ?#lue #nd !et it to # ne6 ?#lue. %! you !#6 in Ch#pter -, # !y*bol e?#lu#te! to the ?#lue o' the ?#ri#ble it n#*e!, !o you c#n get the current ?#lue !i*ply by re'erring to the ?#ri#ble. &o #!!ign # ne6 ?#lue to # binding, you u!e the SETF *#cro, Co**on i!p@! gener#l-purpo!e #!!ign*ent oper#tor. &he b#!ic 'or* o' SETF i! #! 'ollo6!:
1set(#place#value3
7ec#u!e SETF i! # *#cro, it c#n e.#*ine the 'or* o' the place it@! #!!igning to #nd e.p#nd into #ppropri#te lo6er-le?el oper#tion! to *#nipul#te th#t pl#ce. When the pl#ce i! # ?#ri#ble, it e.p#nd! into # c#ll to the !peci#l oper#tor SETQ, 6hich, #! # !peci#l oper#tor, h#! #cce!! to both le.ic#l #nd dyn#*ic binding!.15 /or in!t#nce, to #!!ign the ?#lue 10 to the ?#ri#ble ), you c#n 6rite thi!:
1set(#)#0 3
%! I di!cu!!ed e#rlier, #!!igning # ne6 ?#lue to # binding h#! no e''ect on #ny other binding! o' th#t ?#ri#ble. %nd it doe!n@t h#?e #ny e''ect on the ?#lue th#t 6#! !tored in the binding prior to the #!!ign*ent. &hu!, the SETF in thi! 'unction:
1de('n#(oo#1)3#1set(#)#0 33
6ill h#?e no e''ect on #ny ?#lue out!ide o' (oo. &he binding th#t 6#! cre#ted 6hen (oo 6#! c#lled i! !et to 10, i**edi#tely repl#cing 6h#te?er ?#lue 6#! p#!!ed #! #n #rgu*ent. In p#rticul#r, # 'or* !uch #! the 'ollo6ing:
1let#11?#! 33 ##1(oo#?3 ##1print#?33
6ill print 20, not 10, #! it@! the ?#lue o' ? th#t@! p#!!ed to (oo 6here it@! brie'ly the ?#lue o' the ?#ri#ble ) be'ore the SETF gi?e! ) # ne6 ?#lue. SETF c#n #l!o #!!ign to *ultiple pl#ce! in !eFuence. /or in!t#nce, in!te#d o' the 'ollo6ing:
1set(#)#03 1set(#?#!3
SETF return! the ne6ly #!!igned ?#lue, !o you c#n #l!o ne!t c#ll! to SETF #! in the 'ollo6ing e.pre!!ion, 6hich #!!ign! both ) #nd ? the !#*e r#ndo* ?#lue:
1set(#)#1set(#?#1random#0 333#
&enera%i>ed Assign$ent
1#ri#ble binding!, o' cour!e, #ren@t the only pl#ce! th#t c#n hold ?#lue!. Co**on i!p !upport! co*po!ite d#t# !tructure! !uch #! #rr#y!, h#!h t#ble!, #nd li!t!, #! 6ell #! u!er-de'ined d#t# !tructure!, #ll o' 6hich con!i!t o' *ultiple pl#ce! th#t c#n e#ch hold # ?#lue. I@ll co?er tho!e d#t# !tructure! in 'uture ch#pter!, but 6hile 6e@re on the topic o' #!!ign*ent, you !hould note th#t SETF c#n #!!ign #ny pl#ce # ?#lue. %! I co?er the di''erent co*po!ite d#t# !tructure!, I@ll point out 6hich 'unction! c#n !er?e #! HSETF#ble pl#ce!.H &he !hort ?er!ion, ho6e?er, i! i' you need to #!!ign # ?#lue to # pl#ce, SETF i! #l*o!t cert#inly the tool to u!e. It@! e?en po!!ible to e.tend SETF to #llo6 it to #!!ign to u!er-de'ined pl#ce! though I 6on@t co?er th#t.10 In thi! reg#rd SETF i! no di''erent 'ro* the = #!!ign*ent oper#tor in *o!t C-deri?ed l#ngu#ge!. In tho!e l#ngu#ge!, the = oper#tor #!!ign! ne6 ?#lue! to ?#ri#ble!, #rr#y ele*ent!, #nd 'ield! o' cl#!!e!. In l#ngu#ge! !uch #! Perl #nd Python th#t !upport h#!h t#ble! #! # built-in d#t# type, = c#n #l!o !et the ?#lue! o' indi?idu#l h#!h t#ble entrie!. &#ble 0-1 !u**#riAe! the ?#riou! 6#y! = i! u!ed in tho!e l#ngu#ge!. &#ble 0-1. %!!ign*ent 6ith = in 5ther #ngu#ge! Assigning to ... ?a,a, #, #@@ "er% "ython )#=#0 S \)#=#0 S )#=#0 ... ,aria2%e \aD G#=#0 S aD G#=#0 ... array e%e$ent aD G#=#0 S \hashVC&e?CW#=#0 S hashDC&e?CG#=#0 ... hash ta2%e entry -o.(ield#=#0 S \o-/VC(ieldCW#=#0 S o.(ield#=#0 ... ie%d in o2Aect /!TF 6or9! the !#*e 6#y--the 'ir!t H#rgu*entH to SETF i! # pl#ce to !tore the ?#lue, #nd the !econd #rgu*ent pro?ide! the ?#lue. %! 6ith the = oper#tor in the!e l#ngu#ge!, you u!e the !#*e 'or* to e.pre!! the pl#ce #! you@d nor*#lly u!e to 'etch the ?#lue.12 &hu!, the i!p eFui?#lent! o' the #!!ign*ent! in &#ble 0-1--gi?en th#t AREF i! the #rr#y #cce!! 'unction, GETHASH doe! # h#!h t#ble loo9up, #nd (ield *ight be # 'unction th#t #cce!!e! # !lot n#*ed (ield o' # u!er-de'ined ob<ect-#re #! 'ollo6!:
,imple#variable:####1set(#)#0 3# Irra?:##############1set(#1are(#a# 3#0 3 :ash#table:#########1set(#1gethash#C&e?#hash3#0 3 ,lot#named#C(ieldC:#1set(#1(ield#o3#0 3
:ote th#t SETFing # pl#ce th#t@! p#rt o' # l#rger ob<ect h#! the !#*e !e*#ntic! #! SETFing # ?#ri#ble: the pl#ce i! *odi'ied 6ithout #ny e''ect on the ob<ect th#t 6#! pre?iou!ly !tored in the pl#ce. %g#in, thi! i! !i*il#r to ho6 = beh#?e! in D#?#, Perl, #nd Python.1,
it@! # bit tediou!, co*p#red to the C-!tyle 22) #nd --). In!te#d, you c#n u!e the *#cro! INCF #nd DECF, 6hich incre*ent #nd decre*ent # pl#ce by # cert#in #*ount th#t de'#ult! to 1.
1inc(#)3####===#1set(#)#12#)#033 1dec(#)3####===#1set(#)#1-#)#033 1inc(#)#0 3#===#1set(#)#12#)#0 33
INCF #nd DECF #re e.#*ple! o' # 9ind o' *#cro c#lled modif0 macros. 3odi'y *#cro! #re *#cro! built on top o' SETF th#t *odi'y pl#ce! by #!!igning # ne6 ?#lue b#!ed on the current ?#lue o' the pl#ce. &he *#in bene'it o' *odi'y *#cro! i! th#t they@re *ore conci!e th#n the !#*e *odi'ic#tion 6ritten out u!ing SETF. %ddition#lly, *odi'y *#cro! #re de'ined in # 6#y th#t *#9e! the* !#'e to u!e 6ith pl#ce! 6here the pl#ce e.pre!!ion *u!t be e?#lu#ted only once. % !illy e.#*ple i! thi! e.pre!!ion, 6hich incre*ent! the ?#lue o' #n #rbitr#ry ele*ent o' #n #rr#y:
1inc(#1are(#Uarra?U#1random#1length#Uarra?U3333
% n#i?e tr#n!l#tion o' th#t into # SETF e.pre!!ion *ight loo9 li9e thi!:
1set(#1are(#Uarra?U#1random#1length#Uarra?U333 ######102#1are(#Uarra?U#1random#1length#Uarra?U33333
>o6e?er, th#t doe!n@t 6or9 bec#u!e the t6o c#ll! to RANDOM 6on@t nece!!#rily return the !#*e ?#lue-thi! e.pre!!ion 6ill li9ely gr#b the ?#lue o' one ele*ent o' the #rr#y, incre*ent it, #nd then !tore it b#c9 #! the ne6 ?#lue o' # di''erent ele*ent. &he INCF e.pre!!ion, ho6e?er, doe! the right thing bec#u!e it 9no6! ho6 to t#9e #p#rt thi! e.pre!!ion:
1are(#Uarra?U#1random#1length#Uarra?U333
to pull out the p#rt! th#t could po!!ibly h#?e !ide e''ect! to *#9e !ure they@re e?#lu#ted only once. In thi! c#!e, it 6ould prob#bly e.p#nd into !o*ething *ore or le!! eFui?#lent to thi!:
1let#11tmp#1random#1length#Uarra?U3333 ##1set(#1are(#Uarra?U#tmp3#102#1are(#Uarra?U#tmp3333
In gener#l, *odi'y *#cro! #re gu#r#nteed to e?#lu#te both their #rgu*ent! #nd the !ub'or*! o' the pl#ce 'or* e.#ctly once e#ch, in le't-to-right order. &he *#cro PUSH, 6hich you u!ed in the *ini-d#t#b#!e to #dd ele*ent! to the UdbU ?#ri#ble, i! #nother *odi'y *#cro. 4ou@ll t#9e # clo!er loo9 #t ho6 it #nd it! counterp#rt! POP #nd PUSHNEW 6or9 in Ch#pter 12 6hen I t#l9 #bout ho6 li!t! #re repre!ented in i!p. /in#lly, t6o !lightly e!oteric but u!e'ul *odi'y *#cro! #re ROTATEF #nd SHIFTF. ROTATEF rot#te! ?#lue! bet6een pl#ce!. /or in!t#nce, i' you h#?e t6o ?#ri#ble!, a #nd b, thi! c#ll:
1rotate(#a#b3
!6#p! the ?#lue! o' the t6o ?#ri#ble! #nd return! NIL. Since a #nd b #re ?#ri#ble! #nd you don@t h#?e to 6orry #bout !ide e''ect!, the pre?iou! ROTATEF e.pre!!ion i! eFui?#lent to thi!:
1let#11tmp#a33#1set(#a#b#b#tmp3#nil3
With other 9ind! o' pl#ce!, the eFui?#lent e.pre!!ion u!ing SETF 6ould be Fuite # bit *ore co*ple.. SHIFTF i! !i*il#r e.cept in!te#d o' rot#ting ?#lue! it !hi't! the* to the le't--the l#!t #rgu*ent pro?ide! # ?#lue th#t@! *o?ed to the !econd-to-l#!t #rgu*ent 6hile the re!t o' the ?#lue! #re *o?ed one to the le't. &he origin#l ?#lue o' the 'ir!t #rgu*ent i! !i*ply returned. &hu!, the 'ollo6ing:
1shi(t(#a#b#0 3
i! eFui?#lent--#g#in, !ince you don@t h#?e to 6orry #bout !ide e''ect!--to thi!:
1let#11tmp#a33#1set(#a#b#b#0 3#tmp3
7oth ROTATEF #nd SHIFTF c#n be u!ed 6ith #ny nu*ber o' #rgu*ent! #nd, li9e #ll *odi'y *#cro!, #re gu#r#nteed to e?#lu#te the* e.#ctly once, in le't to right order. With the b#!ic! o' Co**on i!p@! 'unction! #nd ?#ri#ble! under your belt, no6 you@re re#dy to *o?e onto the 'e#ture th#t continue! to di''erenti#te i!p 'ro* other l#ngu#ge!: *#cro!.
1+yn#*ic
?#ri#ble! #re #l!o !o*eti*e! c#lled special variables 'or re#!on! you@ll !ee l#ter in thi! ch#pter. It@! i*port#nt to be #6#re o' thi! !ynony*, #! !o*e 'ol9! B#nd i!p i*ple*ent#tion!C u!e one ter* 6hile other! u!e the other.
2(#rly
i!p! tended to u!e dyn#*ic ?#ri#ble! 'or loc#l ?#ri#ble!, #t le#!t 6hen interpreted. (li!p, the i!p di#lect u!ed in (*#c!, i! # bit o' # thro6b#c9 in thi! re!pect, continuing to !upport only dyn#*ic ?#ri#ble!. 5ther l#ngu#ge! h#?e rec#pitul#ted thi! tr#n!ition 'ro* dyn#*ic to le.ic#l ?#ri#ble!--Perl@! local ?#ri#ble!, 'or in!t#nce, #re dyn#*ic 6hile it! m? ?#ri#ble!, introduced in Perl 5, #re le.ic#l. Python ne?er h#d true dyn#*ic ?#ri#ble! but only introduced true le.ic#l !coping in ?er!ion 2.2. BPython@! le.ic#l ?#ri#ble! #re !till !o*e6h#t li*ited co*p#red to i!p@! bec#u!e o' the con'l#tion o' #!!ign*ent #nd binding in the l#ngu#ge@! !ynt#..C
3%ctu#lly,
it@! not Fuite true to !#y th#t #ll type error! 6ill #l6#y! be detected--it@! po!!ible to u!e option#l decl#r#tion! to tell the co*piler th#t cert#in ?#ri#ble! 6ill #l6#y! cont#in ob<ect! o' # p#rticul#r type #nd to turn o'' runti*e type chec9ing in cert#in region! o' code. >o6e?er, decl#r#tion! o' thi! !ort #re u!ed to opti*iAe code #'ter it h#! been de?eloped #nd debugged, not during nor*#l de?elop*ent.
-%!
#n opti*iA#tion cert#in 9ind! o' ob<ect!, !uch #! integer! belo6 # cert#in !iAe #nd ch#r#cter!, *#y be repre!ented directly in *e*ory 6here other ob<ect! 6ould be repre!ented by # pointer to the #ctu#l ob<ect. >o6e?er, !ince integer! #nd ch#r#cter! #re i**ut#ble, it doe!n@t *#tter th#t there *#y be *ultiple copie! o' Hthe !#*eH ob<ect in di''erent ?#ri#ble!. &hi! i! the root o' the di''erence bet6een EQ #nd EQL di!cu!!ed in Ch#pter -.
5In
co*piler-6riter ter*! Co**on i!p 'unction! #re Hp#!!-by-?#lue.H >o6e?er, the ?#lue! th#t #re p#!!ed #re re'erence! to ob<ect!. &hi! i! !i*il#r to ho6 D#?# #nd Python 6or9.
0&he
?#ri#ble! in LET 'or*! #nd 'unction p#r#*eter! #re cre#ted by e.#ctly the !#*e *ech#ni!*. In '#ct, in !o*e i!p di#lect!--though not Co**on i!p--LET i! !i*ply # *#cro th#t e.p#nd! into # c#ll to #n #nony*ou! 'unction. &h#t i!, in tho!e di#lect!, the 'ollo6ing:
1let#11)#0 33#1(ormat#t#47a4#)33
D#?# di!gui!e! glob#l ?#ri#ble! #! public !t#tic 'ield!, C u!e! e)tern ?#ri#ble!, #nd Python@! *odulele?el #nd Perl@! p#c9#ge-le?el ?#ri#ble! c#n li9e6i!e be #cce!!ed 'ro* #ny6here.
,I'
you !peci'ic#lly 6#nt to re!et # DEFVARed ?#ri#ble, you c#n either !et it directly 6ith SETF or *#9e it unbound u!ing MA+UNBOUND #nd then ree?#lu#te the DEFVAR 'or*.
)&he
!tr#tegy o' te*por#rily re#!!igning S!t#nd#rd-outputS #l!o bre#9! i' the !y!te* i! *ultithre#ded-i' there #re *ultiple thre#d! o' control trying to print to di''erent !tre#*! #t the !#*e ti*e, they@ll #ll try to !et the glob#l ?#ri#ble to the !tre#* they 6#nt to u!e, !to*ping #ll o?er e#ch other. 4ou could u!e # loc9 to control #cce!! to the glob#l ?#ri#ble, but then you@re not re#lly getting the bene'it o' *ultiple concurrent thre#d!, !ince 6h#te?er thre#d i! printing h#! to loc9 out #ll the other thre#d! until it@! done e?en i' they 6#nt to print to # di''erent !tre#*.
10&he
technic#l ter* 'or the inter?#l during 6hich re'erence! *#y be *#de to # binding i! it! e3tent. &hu!, scope #nd e3tent #re co*ple*ent#ry notion!--!cope re'er! to !p#ce 6hile e.tent re'er! to ti*e. e.ic#l ?#ri#ble! h#?e le.ic#l !cope but indefinite e.tent, *e#ning they !tic9 #round 'or #n inde'inite inter?#l, deter*ined by ho6 long they@re needed. +yn#*ic ?#ri#ble!, by contr#!t, h#?e inde'inite !cope !ince they c#n be re'erred to 'ro* #ny6here but d0namic e.tent. &o 'urther con'u!e *#tter!, the co*bin#tion o' inde'inite !cope #nd dyn#*ic e.tent i! 'reFuently re'erred to by the *i!no*er d0namic scope.
11&hough
the !t#nd#rd doe!n@t !peci'y ho6 to incorpor#te *ultithre#ding into Co**on i!p, i*ple*ent#tion! th#t pro?ide *ultithre#ding 'ollo6 the pr#ctice e!t#bli!hed on the i!p *#chine! #nd cre#te dyn#*ic binding! on # per-thre#d b#!i!. % re'erence to # glob#l ?#ri#ble 6ill 'ind the binding *o!t recently e!t#bli!hed in the current thre#d, or the glob#l binding.
12&hi! 13I'
you *u!t 9no6, you c#n loo9 up DECLARE, SPECIAL, #nd LOCALLY in the >yperSpec.
1-Se?er#l
9ey con!t#nt! de'ined by the l#ngu#ge it!el' don@t 'ollo6 thi! con?ention--not le#!t o' 6hich #re T #nd NIL. &hi! i! occ#!ion#lly #nnoying 6hen one 6#nt! to u!e t #! # loc#l ?#ri#ble n#*e. %nother i! PI, 6hich hold! the be!t long-'lo#t #ppro.i*#tion o' the *#the*#tic#l con!t#nt pi.
15So*e 10
old-!chool i!per! pre'er to u!e SETQ 6ith ?#ri#ble!, but *odern !tyle tend! to u!e SETF 'or #ll #!!ign*ent!. oo9 up DEFSETF, DEFINE-SETF-EXPANDER 'or *ore in'or*#tion.
12&he
pre?#lence o' %lgol-deri?ed !ynt#. 'or #!!ign*ent 6ith the Hpl#ceH on the le't !ide o' the = #nd the ne6 ?#lue on the right !ide h#! !p#6ned the ter*inology lvalue, !hort 'or Hle't ?#lue,H *e#ning !o*ething th#t c#n be #!!igned to, #nd rvalue, *e#ning !o*ething th#t pro?ide! # ?#lue. % co*piler h#c9er 6ould !#y, HSETF tre#t! it! 'ir!t #rgu*ent #! #n l?#lue.H
1,C
progr#**er! *#y 6#nt to thin9 o' ?#ri#ble! #nd other pl#ce! #! holding # pointer to the re#l ob<ectG #!!igning to # ?#ri#ble !i*ply ch#nge! 6h#t ob<ect it point! to 6hile #!!igning to # p#rt o' # co*po!ite ob<ect i! !i*il#r to indirecting through the pointer to the #ctu#l ob<ect. CEE progr#**er! !hould note th#t the beh#?ior o' = in CEE 6hen de#ling 6ith ob<ect!--n#*ely, # *e*ber6i!e copy--i! Fuite idio!yncr#tic.
+e?elop*ent Lit BD+LC #re 6ritten in HpureH D#?#. 5ne #d?#nt#ge o' de'ining l#ngu#ge! in ter*! o' # core plu! # !t#nd#rd libr#ry i! it *#9e! the* e#!ier to under!t#nd #nd i*ple*ent. 7ut the re#l bene'it i! in ter*! o' e.pre!!i?ene!!--!ince *uch o' 6h#t you thin9 o' #! Hthe l#ngu#geH i! re#lly <u!t # libr#ry--the l#ngu#ge i! e#!y to e.tend. I' C doe!n@t h#?e # 'unction to do !o*e thing or #nother th#t you need, you c#n 6rite th#t 'unction, #nd no6 you h#?e # !lightly richer ?er!ion o' C. Si*il#rly, in # l#ngu#ge !uch #! D#?# or S*#llt#l9 6here #l*o!t #ll the intere!ting p#rt! o' the Hl#ngu#geH #re de'ined in ter*! o' cl#!!e!, by de'ining ne6 cl#!!e! you e.tend the l#ngu#ge, *#9ing it *ore !uited 'or 6riting progr#*! to do 6h#te?er it i! you@re trying to do. While Co**on i!p !upport! both the!e *ethod! o' e.tending the l#ngu#ge, *#cro! gi?e Co**on i!p yet #nother 6#y. %! I di!cu!!ed brie'ly in Ch#pter -, e#ch *#cro de'ine! it! o6n !ynt#., deter*ining ho6 the !-e.pre!!ion! it@! p#!!ed #re turned into i!p 'or*!. With *#cro! #! p#rt o' the core l#ngu#ge it@! po!!ible to build ne6 !ynt#.--control con!truct! !uch #! WHEN, DOLIST, #nd LOOP #! 6ell #! de'inition#l 'or*! !uch #! DEFUN #nd DEFPARAMETER--#! p#rt o' the H!t#nd#rd libr#ryH r#ther th#n h#?ing to h#rd6ire the* into the core. &hi! h#! i*plic#tion! 'or ho6 the l#ngu#ge it!el' i! i*ple*ented, but #! # i!p progr#**er you@ll c#re *ore th#t it gi?e! you #nother 6#y to e.tend the l#ngu#ge, *#9ing it # better l#ngu#ge 'or e.pre!!ing !olution! to your p#rticul#r progr#**ing proble*!. :o6, it *#y !ee* th#t the bene'it! o' h#?ing #nother 6#y to e.tend the l#ngu#ge 6ould be e#!y to recogniAe. 7ut 'or !o*e re#!on # lot o' 'ol9! 6ho h#?en@t #ctu#lly u!ed i!p *#cro!--'ol9! 6ho thin9 nothing o' !pending their d#y! cre#ting ne6 'unction#l #b!tr#ction! or de'ining hier#rchie! o' cl#!!e! to !ol?e their progr#**ing proble*!--get !poo9ed by the ide# o' being #ble to de'ine ne6 !ynt#ctic #b!tr#ction!. &he *o!t co**on c#u!e o' *#crophobi# !ee*! to be b#d e.perience! 6ith other H*#croH !y!te*!. Si*ple 'e#r o' the un9no6n no doubt pl#y! # role, too. &o #?oid triggering #ny *#crophobic re#ction!, I@ll e#!e into the !ub<ect by di!cu!!ing !e?er#l o' the !t#nd#rd control-con!truct *#cro! de'ined by Co**on i!p. &he!e #re !o*e o' the thing! th#t, i' i!p didn@t h#?e *#cro!, 6ould h#?e to be built into the l#ngu#ge core. When you u!e the*, you don@t h#?e to c#re th#t they@re i*ple*ented #! *#cro!, but they pro?ide # good e.#*ple o' !o*e o' the thing! you c#n do 6ith *#cro!.2 In the ne.t ch#pter, I@ll !ho6 you ho6 you c#n de'ine your o6n *#cro!.
&he condition i! e?#lu#ted #nd, i' it! ?#lue i! non-NIL, the then)form i! e?#lu#ted #nd the re!ulting ?#lue returned. 5ther6i!e, the else)form, i' #ny, i! e?#lu#ted #nd it! ?#lue returned. I' condition i! NIL #nd there@! no else)form, then the IF return! NIL.
1i(#1/#!#33#4H'p4#48ope43#==/#48ope4 1i(#1/#!#33#4H'p43########==/#89L 1i(#1/#3#!3#4H'p4#48ope43#==/#4H'p4
>o6e?er, IF i!n@t #ctu#lly !uch # gre#t !ynt#ctic con!truct bec#u!e the then)form #nd else)form #re e#ch re!tricted to being # !ingle i!p 'or*. &hi! *e#n! i' you 6#nt to per'or* # !eFuence o' #ction! in either cl#u!e, you need to 6r#p the* in !o*e other !ynt#.. /or in!t#nce, !uppo!e in the *iddle o' # !p#*-'iltering progr#* you 6#nted to both 'ile # *e!!#ge #! !p#* #nd upd#te the !p#* d#t#b#!e 6hen # *e!!#ge i! !p#*. 4ou c#n@t 6rite thi!:
bec#u!e the c#ll to 'pdate-spam-database 6ill be tre#ted #! the el!e cl#u!e, not #! p#rt o' the then cl#u!e. %nother !peci#l oper#tor, PROGN, e.ecute! #ny nu*ber o' 'or*! in order #nd return! the ?#lue o' the l#!t 'or*. So you could get the de!ired beh#?ior by 6riting the 'ollo6ing:
1i(#1spam-p#c'rrent-message3 ####1progn ######1(ile-in-spam-(older#c'rrent-message3 ######1'pdate-spam-database#c'rrent-message333
&h#t@! not too horrible. 7ut gi?en the nu*ber o' ti*e! you@ll li9ely h#?e to u!e thi! idio*, it@! not h#rd to i*#gine th#t you@d get tired o' it #'ter # 6hile. HWhy,H you *ight #!9 your!el', Hdoe!n@t i!p pro?ide # 6#y to !#y 6h#t I re#lly 6#nt, n#*ely, @When 3 i! true, do thi!, th#t, #nd the other thing@"H In other 6ord!, #'ter # 6hile you@d notice the p#ttern o' #n IF plu! # PROGN #nd 6i!h 'or # 6#y to #b!tr#ct #6#y the det#il! r#ther th#n 6riting the* out e?ery ti*e. &hi! i! e.#ctly 6h#t *#cro! pro?ide. In thi! c#!e, Co**on i!p co*e! 6ith # !t#nd#rd *#cro, WHEN, 6hich let! you 6rite thi!:
1when#1spam-p#c'rrent-message3 ##1(ile-in-spam-(older#c'rrent-message3 ##1'pdate-spam-database#c'rrent-message33
7ut i' it 6#!n@t built into the !t#nd#rd libr#ry, you could de'ine WHEN your!el' 6ith # *#cro !uch #! thi!, u!ing the b#c9Fuote not#tion I di!cu!!ed in Ch#pter 3:3
1de(macro#when#1condition#>rest#bod?3 ##B1i(#5condition#1progn#5Pbod?333
% counterp#rt to the WHEN *#cro i! UNLESS, 6hich re?er!e! the condition, e?#lu#ting it! body 'or*! only i' the condition i! '#l!e. In other 6ord!:
1de(macro#'nless#1condition#>rest#bod?3 ##B1i(#1not#5condition3#1progn#5Pbod?333
%d*ittedly, the!e #re pretty tri?i#l *#cro!. &here@! no deep bl#c9 *#gic hereG they <u!t #b!tr#ct #6#y # 'e6 l#ngu#ge-le?el boo99eeping det#il!, #llo6ing you to e.pre!! your true intent # bit *ore cle#rly. 7ut their ?ery tri?i#lity *#9e! #n i*port#nt point: bec#u!e the *#cro !y!te* i! built right into the l#ngu#ge, you c#n 6rite tri?i#l *#cro! li9e WHEN #nd UNLESS th#t gi?e you !*#ll but re#l g#in! in cl#rity th#t #re then *ultiplied by the thou!#nd! o' ti*e! you u!e the*. In Ch#pter! 2-, 20, #nd 31 you@ll !ee ho6 *#cro! c#n #l!o be u!ed on # l#rger !c#le, cre#ting 6hole do*#in-!peci'ic e*bedded l#ngu#ge!. 7ut 'ir!t let@! 'ini!h our di!cu!!ion o' the !t#nd#rd control-con!truct *#cro!.
#7:1
%nother ti*e r#6 IF e.pre!!ion! c#n get ugly i! 6hen you h#?e # *ultibr#nch condition#l: i' a do 3, el!e i' b do 0G el!e do 6. &here@! no logic#l proble* 6riting !uch # ch#in o' condition#l e.pre!!ion! 6ith <u!t IF, but it@! not pretty.
1i(#a ####1do-)3
%nd it 6ould be e?en 6or!e i' you needed to include *ultiple 'or*! in the then cl#u!e!, reFuiring PROGN!. So, not !urpri!ingly, Co**on i!p pro?ide! # *#cro 'or e.pre!!ing *ultibr#nch condition#l!: COND. &hi! i! the b#!ic !9eleton:
1cond ##1test-1#formU3 ######. ######. ######. ##1test-N#formU33
(#ch ele*ent o' the body repre!ent! one br#nch o' the condition#l #nd con!i!t! o' # li!t cont#ining # condition 'or* #nd Aero or *ore 'or*! to be e?#lu#ted i' th#t br#nch i! cho!en. &he condition! #re e?#lu#ted in the order the br#nche! #ppe#r in the body until one o' the* e?#lu#te! to true. %t th#t point, the re*#ining 'or*! in th#t br#nch #re e?#lu#ted, #nd the ?#lue o' the l#!t 'or* in the br#nch i! returned #! the ?#lue o' the COND #! # 6hole. I' the br#nch cont#in! no 'or*! #'ter the condition, the ?#lue o' the condition i! returned in!te#d. 7y con?ention, the br#nch repre!enting the 'in#l el!e cl#u!e in #n i';el!e-i' ch#in i! 6ritten 6ith # condition o' T. %ny non-NIL ?#lue 6ill 6or9, but # T !er?e! #! # u!e'ul l#nd*#r9 6hen re#ding the code. &hu!, you c#n 6rite the pre?iou! ne!ted IF e.pre!!ion u!ing COND li9e thi!:
1cond#1a#1do-)33 ######1b#1do-?33 ######1t#1do-*333
Looping
Control con!truct! #re the other *#in 9ind o' looping con!truct!. Co**on i!p@! looping '#cilitie! #re-in #ddition to being Fuite po6er'ul #nd 'le.ible--#n intere!ting le!!on in the h#?e-your-c#9e-#nd-e#t-ittoo !tyle o' progr#**ing th#t *#cro! pro?ide. %! it turn! out, none o' i!p@! 25 !peci#l oper#tor! directly !upport !tructured looping. %ll o' i!p@! looping control con!truct! #re *#cro! built on top o' # p#ir o' !peci#l oper#tor! th#t pro?ide # pri*iti?e goto '#cility.- i9e *#ny good #b!tr#ction!, !ynt#ctic or other6i!e, i!p@! looping *#cro! #re built #! # !et o' l#yered #b!tr#ction! !t#rting 'ro* the b#!e pro?ided by tho!e t6o !peci#l oper#tor!. %t the botto* Ble#?ing #!ide the !peci#l oper#tor!C i! # ?ery gener#l looping con!truct, DO. While ?ery po6er'ul, DO !u''er!, #! do *#ny gener#l-purpo!e #b!tr#ction!, 'ro* being o?er9ill 'or !i*ple !itu#tion!. So i!p #l!o pro?ide! t6o other *#cro!, DOLIST #nd DOTIMES, th#t #re le!! 'le.ible th#n DO but pro?ide con?enient !upport 'or the co**on c#!e! o' looping o?er the ele*ent! o' # li!t #nd counting loop!. While #n i*ple*ent#tion c#n i*ple*ent the!e *#cro! ho6e?er it 6#nt!, they@re typic#lly i*ple*ented #! *#cro! th#t e.p#nd into #n eFui?#lent DO loop. &hu!, DO pro?ide! # b#!ic !tructured looping con!truct on top o' the underlying pri*iti?e! pro?ided by Co**on i!p@! !peci#l oper#tor!, #nd DOLIST #nd DOTIMES pro?ide t6o e#!ier-to-u!e, i' le!! gener#l, con!truct!. %nd, #! you@ll !ee in the ne.t ch#pter, you c#n build your o6n looping con!truct! on top o' DO 'or !itu#tion! 6here DOLIST #nd DOTIMES don@t *eet your need!. /in#lly, the LOOP *#cro pro?ide! # 'ull-blo6n *ini-l#ngu#ge 'or e.pre!!ing looping con!truct! in # non- i!py, (ngli!h-li9e Bor #t le#!t %lgol-li9eC l#ngu#ge. So*e i!p h#c9er! lo?e LOOPG other! h#te it. LOOP@! '#n! li9e it bec#u!e it pro?ide! # conci!e 6#y to e.pre!! cert#in co**only needed looping con!truct!. It! detr#ctor! di!li9e it bec#u!e it@! not i!py enough. 7ut 6hiche?er !ide one co*e! do6n on, it@! # re*#r9#ble e.#*ple o' the po6er o' *#cro! to #dd ne6 con!truct! to the l#ngu#ge.
When the loop !t#rt!, the list)form i! e?#lu#ted once to produce # li!t. &hen the body o' the loop i! e?#lu#ted once 'or e#ch ite* in the li!t 6ith the ?#ri#ble var holding the ?#lue o' the ite*. /or in!t#nce:
$L-+,-./#1dolist#1)#C10#!#333#1print#)33 0 ! 3 89L
8!ed thi! 6#y, the DOLIST 'or* #! # 6hole e?#lu#te! to NIL. I' you 6#nt to bre#9 out o' # DOLIST loop be'ore the end o' the li!t, you c#n u!e RETURN.
$L-+,-./#1dolist#1)#C10#!#333#1print#)3#1i(#1evenp#)3#1ret'rn333 0 !
89L
DOTIMES i! the high-le?el looping con!truct 'or counting loop!. &he b#!ic te*pl#te i! *uch the !#*e #! DOLIST@!.
1dotimes#1var#count-form3 ##body-formU3
&he count)form *u!t e?#lu#te to #n integer. (#ch ti*e through the loop var hold! !ucce!!i?e integer! 'ro* 0 to one le!! th#n th#t nu*ber. /or in!t#nce:
$L-+,-./#1dotimes#1i#43#1print#i33 0 ! 3 89L
%! 6ith DOLIST, you c#n u!e RETURN to bre#9 out o' the loop e#rly. 7ec#u!e the body o' both DOLIST #nd DOTIMES loop! c#n cont#in #ny 9ind o' e.pre!!ion!, you c#n #l!o ne!t loop!. /or e.#*ple, to print out the ti*e! t#ble! 'ro* 0#]#0#=#0 to ! #]#! #=#4 , you c#n 6rite thi! p#ir o' ne!ted DOTIMES loop!:
1dotimes#1)#! 3 ##1dotimes#1?#! 3 ####1(ormat#t#473d#4#1U#102#)3#102#?3333 ##1(ormat#t#476433
17
While DOLIST #nd DOTIMES #re con?enient #nd e#!y to u!e, they #ren@t 'le.ible enough to u!e 'or #ll loop!. /or in!t#nce, 6h#t i' you 6#nt to !tep *ultiple ?#ri#ble! in p#r#llel" 5r u!e #n #rbitr#ry e.pre!!ion to te!t 'or the end o' the loop" I' neither DOLIST nor DOTIMES *eet your need!, you !till h#?e #cce!! to the *ore gener#l DO loop. Where DOLIST #nd DOTIMES pro?ide only one loop ?#ri#ble, DO let! you bind #ny nu*ber o' ?#ri#ble! #nd gi?e! you co*plete control o?er ho6 they ch#nge on e#ch !tep through the loop. 4ou #l!o get to de'ine the te!t th#t deter*ine! 6hen to end the loop #nd c#n pro?ide # 'or* to e?#lu#te #t the end o' the loop to gener#te # return ?#lue 'or the DO e.pre!!ion #! # 6hole. &he b#!ic te*pl#te loo9! li9e thi!:
1do#1variable-definitionU3 ####1end-test-form#result-formU3 ##statementU3
(#ch variable)definition introduce! # ?#ri#ble th#t 6ill be in !cope in the body o' the loop. &he 'ull 'or* o' # !ingle ?#ri#ble de'inition i! # li!t cont#ining three ele*ent!.
1var#init-form#step-form3
&he init)form 6ill be e?#lu#ted #t the beginning o' the loop #nd the re!ulting ?#lue! bound to the ?#ri#ble var. 7e'ore e#ch !ub!eFuent iter#tion o' the loop, the step)form 6ill be e?#lu#ted #nd the ne6 ?#lue #!!igned to var. &he step)form i! option#lG i' it@! le't out, the ?#ri#ble 6ill 9eep it! ?#lue 'ro*
iter#tion to iter#tion unle!! you e.plicitly #!!ign it # ne6 ?#lue in the loop body. %! 6ith the ?#ri#ble de'inition! in # LET, i' the init)form i! le't out, the ?#ri#ble i! bound to NIL. %l!o #! 6ith LET, you c#n u!e # pl#in ?#ri#ble n#*e #! !horth#nd 'or # li!t cont#ining <u!t the n#*e. %t the beginning o' e#ch iter#tion, #'ter #ll the loop ?#ri#ble! h#?e been gi?en their ne6 ?#lue!, the end)test)form i! e?#lu#ted. %! long #! it e?#lu#te! to NIL, the iter#tion proceed!, e?#lu#ting the statements in order. When the end)test)form e?#lu#te! to true, the result)forms #re e?#lu#ted, #nd the ?#lue o' the l#!t re!ult 'or* i! returned #! the ?#lue o' the DO e.pre!!ion. %t e#ch !tep o' the iter#tion the !tep 'or*! 'or #ll the ?#ri#ble! #re e?#lu#ted be'ore #!!igning #ny o' the ?#lue! to the ?#ri#ble!. &hi! *e#n! you c#n re'er to #ny o' the other loop ?#ri#ble! in the !tep 'or*!.0 &h#t i!, in # loop li9e thi!:
1do#11n# #102#n33 #####1c'r# #ne)t3 #####1ne)t#0#12#c'r#ne)t333 ####11=#0 #n3#c'r33
the !tep 'or*! 102#n3, ne)t, #nd 12#c'r#ne)t3 #re #ll e?#lu#ted u!ing the old ?#lue! o' n, c'r, #nd ne)t. 5nly #'ter #ll the !tep 'or*! h#?e been e?#lu#ted #re the ?#ri#ble! gi?en their ne6 ?#lue!. B3#the*#tic#lly inclined re#der! *#y notice th#t thi! i! # p#rticul#rly e''icient 6#y o' co*puting the ele?enth /ibon#cci nu*ber.C &hi! e.#*ple #l!o illu!tr#te! #nother ch#r#cteri!tic o' DO--bec#u!e you c#n !tep *ultiple ?#ri#ble!, you o'ten don@t need # body #t #ll. 5ther ti*e!, you *#y le#?e out the re!ult 'or*, p#rticul#rly i' you@re <u!t u!ing the loop #! # control con!truct. &hi! 'le.ibility, ho6e?er, i! the re#!on th#t DO e.pre!!ion! c#n be # bit cryptic. Where e.#ctly do #ll the p#renthe!e! go" &he be!t 6#y to under!t#nd # DO e.pre!!ion i! to 9eep in *ind the b#!ic te*pl#te.
,do#,variable-definitionU####,end-test-form#result-formU##statementU-
&he !i. p#renthe!e! in th#t te*pl#te #re the only one! reFuired by the DO it!el'. 4ou need one p#ir to enclo!e the ?#ri#ble decl#r#tion!, one p#ir to enclo!e the end te!t #nd re!ult 'or*!, #nd one p#ir to enclo!e the 6hole e.pre!!ion. 5ther 'or*! 6ithin the DO *#y reFuire their o6n p#renthe!e!--?#ri#ble de'inition! #re u!u#lly li!t!, 'or in!t#nce. %nd the te!t 'or* i! o'ten # 'unction c#ll. 7ut the !9eleton o' # DO loop 6ill #l6#y! be the !#*e. >ere #re !o*e e.#*ple DO loop! 6ith the !9eleton in bold:
,do#,1i# #102#i33####,1/=#i#43##1print#i3-
:otice th#t the re!ult 'or* h#! been o*itted. &hi! i!, ho6e?er, not # p#rticul#rly idio*#tic u!e o' DO, #! thi! loop i! *uch *ore !i*ply 6ritten u!ing DOTIMES.2
1dotimes#1i#43#1print#i33
/in#lly, the ne.t loop de*on!tr#te! # DO loop th#t bind! no ?#ri#ble!. It loop! 6hile the current ti*e i! le!! th#n the ?#lue o' # glob#l ?#ri#ble, printing HW#itingH once # *inute. :ote th#t e?en 6ith no loop ?#ri#ble!, you !till need the e*pty ?#ri#ble! li!t.
,do#,####,1/#1get-'niversal-time3#Usome-('t're-dateU3##1(ormat#t#4Waiting7643 ##1sleep#6 3-#
&he 'or*! in body #re e?#lu#ted e#ch ti*e through the loop, 6hich 6ill iter#te 'ore?er unle!! you u!e RETURN to bre#9 out. /or e.#*ple, you could 6rite the pre?iou! DO loop 6ith # !i*ple LOOP.
1loop ##1when#1/#1get-'niversal-time3#Usome-('t're-dateU3 ####1ret'rn33 ##1(ormat#t#4Waiting7643 ##1sleep#6 33
&he e.tended LOOP i! Fuite # di''erent be#!t. It@! di!tingui!hed by the u!e o' cert#in loop $e0words th#t i*ple*ent # !peci#l-purpo!e l#ngu#ge 'or e.pre!!ing looping idio*!. It@! 6orth noting th#t not #ll i!per! lo?e the e.tended LOOP l#ngu#ge. %t le#!t one o' Co**on i!p@! origin#l de!igner! h#ted it. LOOP@! detr#ctor! co*pl#in th#t it! !ynt#. i! tot#lly un- i!py Bin other 6ord!, not enough p#renthe!e!C. LOOP@! '#n! counter th#t th#t@! the point: co*plic#ted looping con!truct! #re h#rd enough to under!t#nd 6ithout 6r#pping the* up in DO@! cryptic !ynt#.. It@! better, they !#y, to h#?e # !lightly *ore ?erbo!e !ynt#. th#t gi?e! you !o*e clue! 6h#t the hec9 i! going on. /or in!t#nce, here@! #n idio*#tic DO loop th#t collect! the nu*ber! 'ro* 1 to 10 into # li!t:
1do#11n'ms#nil3#1i#0#102#i333 ####11/#i#0 3#1nreverse#n'ms33 ##1p'sh#i#n'ms33#==/#10#!#3#4#"#6#Q#R#9#0 3
% !e#!oned i!per 6on@t h#?e #ny trouble under!t#nding th#t code--it@! <u!t # *#tter o' under!t#nding the b#!ic 'or* o' # DO loop #nd recogniAing the PUSH;NREVERSE idio* 'or building up # li!t. 7ut it@! not e.#ctly tr#n!p#rent. &he LOOP ?er!ion, on the other h#nd, i! #l*o!t under!t#nd#ble #! #n (ngli!h !entence.
1loop#(or#i#(rom#0#to#0 #collecting#i3#==/#10#!#3#4#"#6#Q#R#9#0 3
&he 'ollo6ing #re !o*e *ore e.#*ple! o' !i*ple u!e! o' LOOP. &hi! !u*! the 'ir!t ten !Fu#re!:
1loop#(or#)#(rom#0#to#0 #s'mming#1e)pt#)#!33#==/#3R"
&hi! co*pute! the ele?enth /ibon#cci nu*ber, !i*il#r to the DO loop u!ed e#rlier:
1loop#(or#i#below#0 ######and#a#=# #then#b ######and#b#=#0#then#12#b#a3 ######(inall?#1ret'rn##a33
&he !y*bol! across, and, below, collecting, co'nting, (inall?, (or, (rom, s'mming, then, #nd to #re !o*e o' the loop 9ey6ord! 6ho!e pre!ence identi'ie! the!e #! in!t#nce! o' the e.tended LOOP. , I@ll !#?e the det#il! o' LOOP 'or Ch#pter 22, but it@! 6orth noting here #! #nother e.#*ple o' the 6#y *#cro! c#n be u!ed to e.tend the b#!e l#ngu#ge. While LOOP pro?ide! it! o6n l#ngu#ge 'or e.pre!!ing looping con!truct!, it doe!n@t cut you o'' 'ro* the re!t o' i!p. &he loop 9ey6ord! #re p#r!ed #ccording to loop@! gr#**#r, but the re!t o' the code in # LOOP i! regul#r i!p code. %nd it@! 6orth pointing out one *ore ti*e th#t 6hile the LOOP *#cro i! Fuite # bit *ore co*plic#ted th#n *#cro! !uch #! WHEN or UNLESS, it is <u!t #nother *#cro. I' it h#dn@t been included in the !t#nd#rd libr#ry, you could i*ple*ent it your!el' or get # third-p#rty libr#ry th#t doe!. With th#t I@ll conclude our tour o' the b#!ic control-con!truct *#cro!. :o6 you@re re#dy to t#9e # clo!er loo9 #t ho6 to de'ine your o6n *#cro!.
1&o
!ee 6h#t thi! *i!under!t#nding loo9! li9e, 'ind #ny longi!h 8!enet thre#d cro!!-po!ted bet6een co*p.l#ng.li!p #nd #ny other co*p.l#ng.S group 6ith macro in the !ub<ect. % rough p#r#phr#!e goe! li9e thi!: i!pni9: H i!p i! the be!t bec#u!e o' it! *#cro!PHG 5therni9: H4ou thin9 i!p i! good because of *#cro!"P 7ut *#cro! #re horrible #nd e?ilG i!p *u!t be horrible #nd e?il.H
2%nother
i*port#nt cl#!! o' l#ngu#ge con!truct! th#t #re de'ined u!ing *#cro! #re #ll the de'inition#l con!truct! !uch #! DEFUN, DEFPARAMETER, DEFVAR, #nd other!. In Ch#pter 2- you@ll de'ine your o6n de'inition#l *#cro! th#t 6ill #llo6 you to conci!ely 6rite code 'or re#ding #nd 6riting bin#ry d#t#.
34ou
c#n@t #ctu#lly 'eed thi! de'inition to i!p bec#u!e it@! illeg#l to rede'ine n#*e! in the $;%%;8L9,T p#c9#ge 6here WHEN co*e! 'ro*. I' you re#lly 6#nt to try 6riting !uch # *#cro, you@d need to ch#nge the n#*e to !o*ething el!e, !uch #! m?-when.
-&he
!peci#l oper#tor!, i' you *u!t 9no6, #re TAGBODY #nd GO. &here@! no need to di!cu!! the* no6, but I@ll co?er the* in Ch#pter 20.
5DOLIST
i! !i*il#r to Perl@! (oreach or Python@! (or. D#?# #dded # !i*il#r 9ind o' loop con!truct
6ith the Henh#ncedH (or loop in D#?# 1.5, #! p#rt o' DS$-201. :otice 6h#t # di''erence *#cro! *#9e. % i!p progr#**er 6ho notice! # co**on p#ttern in their code c#n 6rite # *#cro to gi?e the*!el?e! # !ource-le?el #b!tr#ction o' th#t p#ttern. % D#?# progr#**er 6ho notice! the !#*e p#ttern h#! to con?ince Sun th#t thi! p#rticul#r #b!tr#ction i! 6orth #dding to the l#ngu#ge. &hen Sun h#! to publi!h # DS$ #nd con?ene #n indu!try-6ide He.pert groupH to h#!h e?erything out. &h#t proce!!--#ccording to Sun--t#9e! #n #?er#ge o' 1, *onth!. %'ter th#t, the co*piler 6riter! #ll h#?e to go upgr#de their co*piler! to !upport the ne6 'e#ture. %nd e?en once the D#?# progr#**er@! '#?orite co*piler !upport! the ne6 ?er!ion o' D#?#, they prob#bly still c#n@t u!e the ne6 'e#ture until they@re #llo6ed to bre#9 !ource co*p#tibility 6ith older ?er!ion! o' D#?#. So #n #nnoy#nce th#t Co**on i!p progr#**er! c#n re!ol?e 'or the*!el?e! 6ithin 'i?e *inute! pl#gue! D#?# progr#**er! 'or ye#r!.
0% ?#ri#nt 2&he
o' DO, DO*, #!!ign! e#ch ?#ri#ble it! ?#lue be'ore e?#lu#ting the !tep 'or* 'or !ub!eFuent ?#ri#ble!. /or *ore det#il!, con!ult your '#?orite Co**on i!p re'erence. DOTIMES i! #l!o pre'erred bec#u!e the *#cro e.p#n!ion 6ill li9ely include decl#r#tion! th#t #llo6 the co*piler to gener#te *ore e''icient code.
,Loop
$e0words i! # bit o' # *i!no*er !ince they #ren@t 9ey6ord !y*bol!. In '#ct, LOOP doe!n@t c#re 6h#t p#c9#ge the !y*bol! #re 'ro*. When the LOOP *#cro p#r!e! it! body, it con!ider! #ny #ppropri#tely n#*ed !y*bol! eFui?#lent. 4ou could e?en u!e true 9ey6ord! i' you 6#nted--:(or, :across, #nd !o on--bec#u!e they #l!o h#?e the correct n#*e. 7ut *o!t 'ol9! <u!t u!e pl#in !y*bol!. 7ec#u!e the loop 9ey6ord! #re u!ed only #! !ynt#ctic *#r9er!, it doe!n@t *#tter i' they@re u!ed 'or other purpo!e!--#! 'unction or ?#ri#ble n#*e!.
5nce you under!t#nd the di''erence bet6een *#cro! #nd 'unction!, the tight integr#tion o' *#cro! in the l#ngu#ge 6ill be # huge bene'it. 7ut in the *e#nti*e, it@! # 'reFuent !ource o' con'u!ion 'or ne6 i!per!. &he 'ollo6ing !tory, 6hile not true in # hi!toric#l or technic#l !en!e, trie! to #lle?i#te the con'u!ion by gi?ing you # 6#y to thin9 #bout ho6 *#cro! 6or9.
in the +(/3%C$5!. Since the i!p progr#*! in the note! did #ll the re#l 6or9, 9eeping up 6ith the e*#il! 6#! no proble*. 3#c !uddenly h#d # lot o' ti*e on hi! h#nd! #nd 6ould !it in hi! o''ice d#ydre#*ing #bout 6hite-!#nd be#che!, cle#r blue oce#n 6#ter, #nd drin9! 6ith little p#per u*brell#! in the*. Se?er#l *onth! l#ter the progr#**er! re#liAed nobody h#d !een 3#c 'or Fuite !o*e ti*e. When they 6ent to hi! o''ice, they 'ound # thin l#yer o' du!t o?er e?erything, # de!9 littered 6ith tr#?el brochure! 'or ?#riou! tropic#l loc#tion!, #nd the co*puter o''. 7ut the co*piler !till 6or9ed--ho6 could it be" It turned out 3#c h#d *#de one l#!t ch#nge to the co*piler: in!te#d o' e-*#iling note! to 3#c, the co*piler no6 !#?ed the 'unction! de'ined by +(/3%C$5 note! #nd r#n the* 6hen c#lled 'or by the other note!. &he progr#**er! decided there 6#! no re#!on to tell the big bo!!e! 3#c 6#!n@t co*ing to the o''ice #ny*ore. So to thi! d#y, 3#c dr#6! # !#l#ry #nd 'ro* ti*e to ti*e !end! the progr#**er! # po!tc#rd 'ro* one tropic#l loc#le or #nother.
:or*#lly you@d thin9 o' ) #! # ?#ri#ble th#t 6ill hold the #rgu*ent p#!!ed in # c#ll to (oo. 7ut #t *#cro e.p#n!ion ti*e, !uch #! 6hen the co*piler i! running the WHEN *#cro, the only d#t# #?#il#ble i! the !ource code. Since the progr#* i!n@t running yet, there@! no c#ll to (oo #nd thu! no ?#lue #!!oci#ted 6ith ). In!te#d, the ?#lue! the co*piler p#!!e! to WHEN #re the i!p li!t! repre!enting the !ource code, n#*ely, 1/#)#0 3 #nd 1print#Cbig3. Suppo!e th#t WHEN i! de'ined, #! you !#6 in the pre?iou! ch#pter, 6ith !o*ething li9e the 'ollo6ing *#cro:
1de(macro#when#1condition#>rest#bod?3 ##B1i(#5condition#1progn#5Pbod?333
When the code in (oo i! co*piled, the WHEN *#cro 6ill be run 6ith tho!e t6o 'or*! #! #rgu*ent!. &he p#r#*eter condition 6ill be bound to the 'or* 1/#)#0 3, #nd the 'or* 1print#Cbig3 6ill be collected into # li!t th#t 6ill beco*e the ?#lue o' the &&'(! bod? p#r#*eter. &he b#c9Fuote e.pre!!ion 6ill then gener#te thi! code:
1i(#1/#)#0 3#1progn#1print#Cbig333
by interpol#ting in the ?#lue o' condition #nd !plicing the ?#lue o' bod? into the PROGN.
When i!p i! interpreted, r#ther th#n co*piled, the di!tinction bet6een *#cro e.p#n!ion ti*e #nd runti*e i! le!! cle#r bec#u!e they@re te*por#lly intert6ined. %l!o, the l#ngu#ge !t#nd#rd doe!n@t !peci'y e.#ctly ho6 #n interpreter *u!t h#ndle *#cro!--it could e.p#nd #ll the *#cro! in the 'or* being interpreted #nd then interpret the re!ulting code, or it could !t#rt right in on interpreting the 'or* #nd e.p#nd *#cro! 6hen it hit! the*. In either c#!e, *#cro! #re #l6#y! p#!!ed the une?#lu#ted i!p ob<ect! repre!enting the !ub'or*! o' the *#cro 'or*, #nd the <ob o' the *#cro i! !till to produce code th#t 6ill do !o*ething r#ther th#n to do #nything directly.
1!F+A#R7
%! you !#6 in Ch#pter 3, *#cro! re#lly #re de'ined 6ith DEFMACRO 'or*!, though it !t#nd!--o' cour!e--'or +(/ine 3%C$5, not +e'inition 'or 3#c. &he b#!ic !9eleton o' # DEFMACRO i! Fuite !i*il#r to the !9eleton o' # DEFUN.
1de(macro#name#1parameterU3 ##4;ptional#doc'mentation#string.4 ##body-formU3
i9e # 'unction, # *#cro con!i!t! o' # n#*e, # p#r#*eter li!t, #n option#l docu*ent#tion !tring, #nd # body o' i!p e.pre!!ion!.1 >o6e?er, #! I <u!t di!cu!!ed, the <ob o' # *#cro i!n@t to do #nything directly--it! <ob i! to gener#te code th#t 6ill l#ter do 6h#t you 6#nt. 3#cro! c#n u!e the 'ull po6er o' i!p to gener#te their e.p#n!ion, 6hich *e#n! in thi! ch#pter I c#n only !cr#tch the !ur'#ce o' 6h#t you c#n do 6ith *#cro!. I c#n, ho6e?er, de!cribe # gener#l proce!! 'or 6riting *#cro! th#t 6or9! 'or #ll *#cro! 'ro* the !i*ple!t to the *o!t co*ple.. &he <ob o' # *#cro i! to tr#n!l#te # *#cro 'or*--in other 6ord!, # i!p 'or* 6ho!e 'ir!t ele*ent i! the n#*e o' the *#cro--into code th#t doe! # p#rticul#r thing. So*eti*e! you 6rite # *#cro !t#rting 6ith the code you@d li9e to be #ble to 6rite, th#t i!, 6ith #n e.#*ple *#cro 'or*. 5ther ti*e! you decide to 6rite # *#cro #'ter you@?e 6ritten the !#*e p#ttern o' code !e?er#l ti*e! #nd re#liAe you c#n *#9e your code cle#rer by #b!tr#cting the p#ttern. $eg#rdle!! o' 6hich end you !t#rt 'ro*, you need to 'igure out the other end be'ore you c#n !t#rt 6riting # *#cro: you need to 9no6 both 6here you@re co*ing 'ro* #nd 6here you@re going be'ore you c#n hope to 6rite code to do it #uto*#tic#lly. &hu!, the 'ir!t !tep o' 6riting # *#cro i! to 6rite #t le#!t one e.#*ple o' # c#ll to the *#cro #nd the code into 6hich th#t c#ll !hould e.p#nd. 5nce you h#?e #n e.#*ple c#ll #nd the de!ired e.p#n!ion, you@re re#dy 'or the !econd !tep: 6riting the #ctu#l *#cro code. /or !i*ple *#cro! thi! 6ill be # tri?i#l *#tter o' 6riting # b#c9Fuoted te*pl#te 6ith the *#cro p#r#*eter! plugged into the right pl#ce!. Co*ple. *#cro! 6ill be !igni'ic#nt progr#*! in their o6n right, co*plete 6ith helper 'unction! #nd d#t# !tructure!. %'ter you@?e 6ritten code to tr#n!l#te the e.#*ple c#ll to the #ppropri#te e.p#n!ion, you need to *#9e !ure the #b!tr#ction the *#cro pro?ide! doe!n@t Hle#9H det#il! o' it! i*ple*ent#tion. e#9y *#cro #b!tr#ction! 6ill 6or9 'ine 'or cert#in #rgu*ent! but not other! or 6ill inter#ct 6ith code in the c#lling en?iron*ent in unde!ir#ble 6#y!. %! it turn! out, *#cro! c#n le#9 in # !*#ll h#nd'ul o' 6#y!, #ll o' 6hich #re e#!ily #?oided #! long #! you 9no6 to chec9 'or the*. I@ll di!cu!! ho6 in the !ection HPlugging the e#9!.H &o !u* up, the !tep! to 6riting # *#cro #re #! 'ollo6!: 1. Write # !#*ple c#ll to the *#cro #nd the code it !hould e.p#nd into, or ?ice ?er!#. 2. Write code th#t gener#te! the h#nd6ritten e.p#n!ion 'ro* the #rgu*ent! in the !#*ple c#ll.
:o6 you c#n 6rite the *#cro. /ollo6ing the procedure outlined pre?iou!ly, you need #t le#!t one e.#*ple o' # c#ll to the *#cro #nd the code into 6hich it !hould e.p#nd. Suppo!e you !t#rt 6ith the ide# th#t you 6#nt to be #ble to 6rite thi!:
1do-primes#1p# #093 ##1(ormat#t#47d#4#p33
to e.pre!! # loop th#t e.ecute! the body once e#ch 'or e#ch pri*e nu*ber gre#ter or eFu#l to 0 #nd le!! th#n or eFu#l to 1), 6ith the ?#ri#ble p holding the pri*e nu*ber. It *#9e! !en!e to *odel thi! *#cro on the 'or* o' the !t#nd#rd DOLIST #nd DOTIMES *#cro!G *#cro! th#t 'ollo6 the p#ttern o' e.i!ting *#cro! #re e#!ier to under!t#nd #nd u!e th#n *#cro! th#t introduce gr#tuitou!ly no?el !ynt#.. Without the do-primes *#cro, you could 6rite !uch # loop 6ith DO B#nd the t6o utility 'unction! de'ined pre?iou!lyC li9e thi!:
1do#11p#1ne)t-prime# 3#1ne)t-prime#102#p3333 ####11/#p#0933 ##1(ormat#t#47d#4#p33
:o6 you@re re#dy to !t#rt 6riting the *#cro code th#t 6ill tr#n!l#te 'ro* the 'or*er to the l#tter.
+acro "ara$eters
Since the #rgu*ent! p#!!ed to # *#cro #re i!p ob<ect! repre!enting the !ource code o' the *#cro c#ll, the 'ir!t !tep in #ny *#cro i! to e.tr#ct 6h#te?er p#rt! o' tho!e ob<ect! #re needed to co*pute the e.p#n!ion. /or *#cro! th#t !i*ply interpol#te their #rgu*ent! directly into # te*pl#te, thi! !tep i! tri?i#l: !i*ply de'ining the right p#r#*eter! to hold the di''erent #rgu*ent! i! !u''icient. 7ut thi! #ppro#ch, it !ee*!, 6ill not !u''ice 'or do-primes. &he 'ir!t #rgu*ent to the do-primes c#ll i! # li!t cont#ining the n#*e o' the loop ?#ri#ble, pG the lo6er bound, G #nd the upper bound, 09. 7ut i' you loo9 #t the e.p#n!ion, the li!t #! # 6hole doe!n@t #ppe#r in the e.p#n!ionG the three ele*ent #re !plit up #nd put in di''erent pl#ce!. 4ou could de'ine do-primes 6ith t6o p#r#*eter!, one to hold the li!t #nd # &&'(! p#r#*eter to
hold the body 'or*!, #nd then t#9e #p#rt the li!t by h#nd, !o*ething li9e thi!:
1de(macro#do-primes#1var-and-range#>rest#bod?3 ##1let#11var#1(irst#var-and-range33 ########1start#1second#var-and-range33 ########1end#1third#var-and-range333 ####B1do#115var#1ne)t-prime#5start3#1ne)t-prime#102#5var3333 #########11/#5var#5end33 #######5Pbod?333
In # *o*ent I@ll e.pl#in ho6 the body gener#te! the correct e.p#n!ionG 'or no6 you c#n <u!t note th#t the ?#ri#ble! var, start, #nd end e#ch hold # ?#lue, e.tr#cted 'ro* var-and-range, th#t@! then interpol#ted into the b#c9Fuote e.pre!!ion th#t gener#te! do-primes@! e.p#n!ion. >o6e?er, you don@t need to t#9e #p#rt var-and-range Hby h#ndH bec#u!e *#cro p#r#*eter li!t! #re 6h#t #re c#lled destructuring p#r#*eter li!t!. +e!tructuring, #! the n#*e !ugge!t!, in?ol?e! t#9ing #p#rt # !tructure--in thi! c#!e the li!t !tructure o' the 'or*! p#!!ed to # *#cro. Within # de!tructuring p#r#*eter li!t, # !i*ple p#r#*eter n#*e c#n be repl#ced 6ith # ne!ted p#r#*eter li!t. &he p#r#*eter! in the ne!ted p#r#*eter li!t 6ill t#9e their ?#lue! 'ro* the ele*ent! o' the e.pre!!ion th#t 6ould h#?e been bound to the p#r#*eter the li!t repl#ced. /or in!t#nce, you c#n repl#ce var-and-range 6ith # li!t 1var#start#end3, #nd the three ele*ent! o' the li!t 6ill #uto*#tic#lly be de!tructured into tho!e three p#r#*eter!. %nother !peci#l 'e#ture o' *#cro p#r#*eter li!t! i! th#t you c#n u!e &.o/* #! # !ynony* 'or &&'(!. Se*#ntic#lly &.o/* #nd &&'(! #re eFui?#lent, but *#ny de?elop*ent en?iron*ent! 6ill u!e the pre!ence o' # &.o/* p#r#*eter to *odi'y ho6 they indent u!e! o' the *#cro--typic#lly &.o/* p#r#*eter! #re u!ed to hold # li!t o' 'or*! th#t *#9e up the body o' the *#cro. So you c#n !tre#*line the de'inition o' do-primes #nd gi?e # hint to both hu*#n re#der! #nd your de?elop*ent tool! #bout it! intended u!e by de'ining it li9e thi!:
1de(macro#do-primes#11var#start#end3#>bod?#bod?3 ##B1do#115var#1ne)t-prime#5start3#1ne)t-prime#102#5var3333 #######11/#5var#5end33 #####5Pbod?33
In #ddition to being *ore conci!e, de!tructuring p#r#*eter li!t! #l!o gi?e you #uto*#tic error chec9ing--6ith do-primes de'ined thi! 6#y, i!p 6ill be #ble to detect # c#ll 6ho!e 'ir!t #rgu*ent i!n@t # three-ele*ent li!t #nd 6ill gi?e you # *e#ning'ul error *e!!#ge <u!t #! i' you h#d c#lled # 'unction 6ith too 'e6 or too *#ny #rgu*ent!. %l!o, in de?elop*ent en?iron*ent! !uch #! S I3( th#t indic#te 6h#t #rgu*ent! #re e.pected #! !oon #! you type the n#*e o' # 'unction or *#cro, i' you u!e # de!tructuring p#r#*eter li!t, the en?iron*ent 6ill be #ble to tell you *ore !peci'ic#lly the !ynt#. o' the *#cro c#ll. With the origin#l de'inition, S I3( 6ould tell you do-primes i! c#lled li9e thi!:
1do-primes#var-and-range#>rest#bod?3
7ut 6ith the ne6 de'inition, it c#n tell you th#t # c#ll !hould loo9 li9e thi!:
1do-primes#1var#start#end3#>bod?#bod?3
+e!tructuring p#r#*eter li!t! c#n cont#in &o !"o#$%, &)'*, #nd &&'(! p#r#*eter! #nd c#n cont#in ne!ted de!tructuring li!t!. >o6e?er, you don@t need #ny o' tho!e option! to 6rite do-primes.
B1a#1list#0#!3#c3 1list#Ca#C1list#0#!3#Cc3
B1a#51list#0#!3# 1list#Ca#1list#0#!3#Cc3 1a#10#!3#c3 c3 B1a#5P1list#0#!3# 1append#1list#Ca3#1list#0#!3#1list# 1a#0#!#c3 c3 Cc33 It@! i*port#nt to note th#t b#c9Fuote i! <u!t # con?enience. 7ut it@! # big con?enience. &o #ppreci#te ho6 big, co*p#re the b#c9Fuoted ?er!ion o' do-primes to the 'ollo6ing ?er!ion, 6hich u!e! e.plicit li!t-building code:
1de(macro#do-primes-a#11var#start#end3#>bod?#bod?3 ##1append#C1do3 ##########1list##1list#1list#var #############################1list#Cne)t-prime#start3 #############################1list#Cne)t-prime#1list#C02#var33333 ##########1list#1list#1list#C/#var#end333 ##########bod?33
%! you@ll !ee in # *o*ent, the current i*ple*ent#tion o' do-primes doe!n@t h#ndle cert#in edge c#!e! correctly. 7ut 'ir!t you !hould ?eri'y th#t it #t le#!t 6or9! 'or the origin#l e.#*ple. 4ou c#n te!t it in t6o 6#y!. 4ou c#n te!t it indirectly by !i*ply u!ing it--pre!u*#bly, i' the re!ulting beh#?ior i! correct, the e.p#n!ion i! correct. /or in!t#nce, you c#n type the origin#l e.#*ple@! u!e o' do-primes to the $(P #nd !ee th#t it indeed print! the right !erie! o' pri*e nu*ber!.
$L-+,-./#1do-primes#1p# #093#1(ormat#t#47d#4#p33 !#3#"#Q#00#03#0Q#09 89L
5r you c#n chec9 the *#cro directly by loo9ing #t the e.p#n!ion o' # p#rticul#r c#ll. &he 'unction MACROEXPAND-1 t#9e! #ny i!p e.pre!!ion #! #n #rgu*ent #nd return! the re!ult o' doing one le?el o' *#cro e.p#n!ion.3 7ec#u!e MACROEXPAND-1 i! # 'unction, to p#!! it # liter#l *#cro 'or* you *u!t Fuote it. 4ou c#n u!e it to !ee the e.p#n!ion o' the pre?iou! c#ll.$L-+,-./#1macroe)pand-0#C1do-primes#1p# #093#1(ormat#t#47d#4#p333 1<;#11T#18-[F-T.9%-# 3#18-[F-T.9%-#102#T3333 ####11/#T#0933 ##1E;.%IF#F#47d#4#T33 F
5r, *ore con?eniently, in S I3( you c#n chec9 # *#cro@! e.p#n!ion by pl#cing the cur!or on the opening p#renthe!i! o' # *#cro 'or* in your !ource code #nd typing $-c#.-F to in?o9e the (*#c! 'unction slime-macroe)pand-0, 6hich 6ill p#!! the *#cro 'or* to MACROEXPAND-1 #nd Hpretty printH the re!ult in # te*por#ry bu''er. >o6e?er you get to it, you c#n !ee th#t the re!ult o' *#cro e.p#n!ion i! the !#*e #! the origin#l h#nd6ritten e.p#n!ion, !o it !ee*! th#t do-primes 6or9!.
Pre!u*#bly the intent here i! to loop o?er the pri*e! 'ro* Aero to 6h#te?er r#ndo* nu*ber i! returned by 1random#0 3. >o6e?er, thi! i!n@t 6h#t the current i*ple*ent#tion doe!, #! MACROEXPAND-1 !ho6!.
$L-+,-./#1macroe)pand-0#C1do-primes#1p# #1random#0 1<;#11T#18-[F-T.9%-# 3#18-[F-T.9%-#102#T3333 ####11/#T#1.I8<;%#0 333 ##1E;.%IF#F#47d#4#T33 F 33#1(ormat#t#47d#4#p333
When thi! e.p#n!ion code i! run, RANDOM 6ill be c#lled e#ch ti*e the end te!t 'or the loop i! e?#lu#ted. &hu!, in!te#d o' looping until p i! gre#ter th#n #n initi#lly cho!en r#ndo* nu*ber, thi! loop 6ill iter#te until it h#ppen! to dr#6 # r#ndo* nu*ber le!! th#n or eFu#l to the current ?#lue o' p. While the tot#l nu*ber o' iter#tion! 6ill !till be r#ndo*, it 6ill be dr#6n 'ro* # *uch di''erent di!tribution th#n the uni'or* di!tribution RANDOM return!. &hi! i! # le#9 in the #b!tr#ction bec#u!e, to u!e the *#cro correctly, the c#ller need! to be #6#re th#t the end 'or* i! going to be e?#lu#ted *ore th#n once. 5ne 6#y to plug thi! le#9 6ould be to !i*ply de'ine thi! #! the beh#?ior o' do-primes. 7ut th#t@! not ?ery !#ti!'#ctory--you !hould try to ob!er?e
the Principle o' e#!t %!toni!h*ent 6hen i*ple*enting *#cro!. %nd progr#**er! 6ill typic#lly e.pect the 'or*! they p#!! to *#cro! to be e?#lu#ted no *ore ti*e! th#n #b!olutely nece!!#ry.0 /urther*ore, !ince do-primes i! built on the *odel o' the !t#nd#rd *#cro!, DOTIMES #nd DOLIST, neither o' 6hich c#u!e! #ny o' the 'or*! e.cept tho!e in the body to be e?#lu#ted *ore th#n once, *o!t progr#**er! 6ill e.pect do-primes to beh#?e !i*il#rly. 4ou c#n 'i. the *ultiple e?#lu#tion e#!ily enoughG you <u!t need to gener#te code th#t e?#lu#te! end once #nd !#?e! the ?#lue in # ?#ri#ble to be u!ed l#ter. $ec#ll th#t in # DO loop, ?#ri#ble! de'ined 6ith #n initi#liA#tion 'or* #nd no !tep 'or* don@t ch#nge 'ro* iter#tion to iter#tion. So you c#n 'i. the *ultiple e?#lu#tion proble* 6ith thi! de'inition:
1de(macro#do-primes#11var#start#end3#>bod?#bod?3 ##B1do#11ending-val'e#5end3 ########15var#1ne)t-prime#5start3#1ne)t-prime#102#5var3333 #######11/#5var#ending-val'e33 #####5Pbod?33
8n'ortun#tely, thi! 'i. introduce! t6o ne6 le#9! to the *#cro #b!tr#ction. 5ne ne6 le#9 i! !i*il#r to the *ultiple-e?#lu#tion le#9 you <u!t 'i.ed. 7ec#u!e the initi#liA#tion 'or*! 'or ?#ri#ble! in # DO loop #re e?#lu#ted in the order the ?#ri#ble! #re de'ined, 6hen the *#cro e.p#n!ion i! e?#lu#ted, the e.pre!!ion p#!!ed #! end 6ill be e?#lu#ted be'ore the e.pre!!ion p#!!ed #! start, oppo!ite to the order they #ppe#r in the *#cro c#ll. &hi! le#9 doe!n@t c#u!e #ny proble*! 6hen start #nd end #re liter#l ?#lue! li9e 0 #nd 1). 7ut 6hen they@re 'or*! th#t c#n h#?e !ide e''ect!, e?#lu#ting the* out o' order c#n once #g#in run #'oul o' the Principle o' e#!t %!toni!h*ent. &hi! le#9 i! tri?i#lly plugged by !6#pping the order o' the t6o ?#ri#ble de'inition!.
1de(macro#do-primes#11var#start#end3#>bod?#bod?3 ##B1do#115var#1ne)t-prime#5start3#1ne)t-prime#102#5var333 ########1ending-val'e#5end33 #######11/#5var#ending-val'e33 #####5Pbod?33
&he l#!t le#9 you need to plug 6#! cre#ted by u!ing the ?#ri#ble n#*e ending-val'e. &he proble* i! th#t the n#*e, 6hich ought to be # purely intern#l det#il o' the *#cro i*ple*ent#tion, c#n end up inter#cting 6ith code p#!!ed to the *#cro or in the conte.t 6here the *#cro i! c#lled. &he 'ollo6ing !ee*ingly innocent c#ll to do-primes doe!n@t 6or9 correctly bec#u!e o' thi! le#9:
1do-primes#1ending-val'e# #0 3 ##1print#ending-val'e33
%g#in, MACROEXPAND-1 c#n !ho6 you the proble*. &he 'ir!t c#ll e.p#nd! to thi!:
1do#11ending-val'e#1ne)t-prime# 3#1ne)t-prime#102#ending-val'e333 #####1ending-val'e#0 33 ####11/#ending-val'e#ending-val'e33 ##1print#ending-val'e33
So*e i!p! *#y re<ect thi! code bec#u!e ending-val'e i! u!ed t6ice #! # ?#ri#ble n#*e in the !#*e DO loop. I' not re<ected outright, the code 6ill loop 'ore?er !ince ending-val'e 6ill ne?er be gre#ter th#n it!el'. &he !econd proble* c#ll e.p#nd! to the 'ollo6ing:
1let#11ending-val'e# 33 ##1do#11p#1ne)t-prime# 3#1ne)t-prime#102#p333 #######1ending-val'e#0 33 ######11/#p#ending-val'e33 ####1inc(#ending-val'e#p33 ##ending-val'e3
In thi! c#!e the gener#ted code i! per'ectly leg#l, but the beh#?ior i!n@t #t #ll 6h#t you 6#nt. 7ec#u!e the binding o' ending-val'e e!t#bli!hed by the LET out!ide the loop i! !h#do6ed by the ?#ri#ble 6ith the !#*e n#*e in!ide the DO, the 'or* 1inc(#ending-val'e#p3 incre*ent! the loop ?#ri#ble ending-val'e in!te#d o' the outer ?#ri#ble 6ith the !#*e n#*e, cre#ting #nother in'inite loop.2 Cle#rly, 6h#t you need to p#tch thi! le#9 i! # !y*bol th#t 6ill ne?er be u!ed out!ide the code gener#ted by the *#cro. 4ou could try u!ing # re#lly unli9ely n#*e, but th#t@! no gu#r#ntee. 4ou could #l!o protect your!el' to !o*e e.tent by u!ing p#c9#ge!, #! de!cribed in Ch#pter 21. 7ut there@! # better !olution. &he 'unction GENSYM return! # uniFue !y*bol e#ch ti*e it@! c#lled. &hi! i! # !y*bol th#t h#! ne?er been re#d by the i!p re#der #nd ne?er 6ill be bec#u!e it i!n@t interned in #ny p#c9#ge. &hu!, in!te#d o' u!ing # liter#l n#*e li9e ending-val'e, you c#n gener#te # ne6 !y*bol e#ch ti*e do-primes i! e.p#nded.
1de(macro#do-primes#11var#start#end3#>bod?#bod?3 ##1let#11ending-val'e-name#1gens?m333 ####B1do#115var#1ne)t-prime#5start3#1ne)t-prime#102#5var333 ##########15ending-val'e-name#5end33 #########11/#5var#5ending-val'e-name33 #######5Pbod?333
:ote th#t the code th#t c#ll! GENSYM i!n@t p#rt o' the e.p#n!ionG it run! #! p#rt o' the *#cro e.p#nder #nd thu! cre#te! # ne6 !y*bol e#ch ti*e the *#cro i! e.p#nded. &hi! *#y !ee* # bit !tr#nge #t 'ir!t-ending-val'e-name i! # ?#ri#ble 6ho!e ?#lue i! the n#*e o' #nother ?#ri#ble. 7ut re#lly it@! no di''erent 'ro* the p#r#*eter var 6ho!e ?#lue i! the n#*e o' # ?#ri#ble--the di''erence i! the ?#lue o' var 6#! cre#ted by the re#der 6hen the *#cro 'or* 6#! re#d, #nd the ?#lue o' ending-val'ename i! gener#ted progr#**#tic#lly 6hen the *#cro code run!. With thi! de'inition the t6o pre?iou!ly proble*#tic 'or*! e.p#nd into code th#t 6or9! the 6#y you 6#nt. &he 'ir!t 'or*:
1do-primes#1ending-val'e# #0 3 ##1print#ending-val'e33
:o6 the ?#ri#ble u!ed to hold the ending ?#lue i! the gen!y*ed !y*bol, N:g!040. &he n#*e o' the !y*bol, J!040, 6#! gener#ted by GENSYM but i!n@t !igni'ic#ntG the thing th#t *#tter! i! the ob<ect identity o' the !y*bol. =en!y*ed !y*bol! #re printed in the nor*#l !ynt#. 'or uninterned !y*bol!, 6ith # le#ding N:. &he other pre?iou!ly proble*#tic 'or*:
1let#11ending-val'e# 33 ##1do-primes#1p# #0 3 ####1inc(#ending-val'e#p33 ##ending-val'e3
loo9! li9e thi! i' you repl#ce the do-primes 'or* 6ith it! e.p#n!ion:
1let#11ending-val'e# 33 ##1do#11p#1ne)t-prime# 3#1ne)t-prime#102#p333 #######1N:g!04 #0 33 ######11/#p#N:g!04 33 ####1inc(#ending-val'e#p33 ##ending-val'e3
%g#in, there@! no le#9 !ince the ending-val'e ?#ri#ble bound by the LET !urrounding the doprimes loop i! no longer !h#do6ed by #ny ?#ri#ble! introduced in the e.p#nded code. :ot #ll liter#l n#*e! u!ed in # *#cro e.p#n!ion 6ill nece!!#rily c#u!e # proble*--#! you get *ore e.perience 6ith the ?#riou! binding 'or*!, you@ll be #ble to deter*ine 6hether # gi?en n#*e i! being u!ed in # po!ition th#t could c#u!e # le#9 in # *#cro #b!tr#ction. 7ut there@! no re#l do6n!ide to u!ing # gen!y*ed n#*e <u!t to be !#'e. With th#t 'i., you@?e plugged #ll the le#9! in the i*ple*ent#tion o' do-primes. 5nce you@?e gotten # bit o' *#cro-6riting e.perience under your belt, you@ll le#rn to 6rite *#cro! 6ith the!e 9ind! o' le#9! preplugged. It@! #ctu#lly '#irly !i*ple i' you 'ollo6 the!e rule! o' thu*b: 8nle!! there@! # p#rticul#r re#!on to do other6i!e, include #ny !ub'or*! in the e.p#n!ion in po!ition! th#t 6ill be e?#lu#ted in the !#*e order #! the !ub'or*! #ppe#r in the *#cro c#ll. 8nle!! there@! # p#rticul#r re#!on to do other6i!e, *#9e !ure !ub'or*! #re e?#lu#ted only once by cre#ting # ?#ri#ble in the e.p#n!ion to hold the ?#lue o' e?#lu#ting the #rgu*ent 'or* #nd then u!ing th#t ?#ri#ble #ny6here el!e the ?#lue i! needed in the e.p#n!ion. 8!e GENSYM #t *#cro e.p#n!ion ti*e to cre#te ?#ri#ble n#*e! u!ed in the e.p#n!ion.
+acro4Writing +acros
5' cour!e, there@! no re#!on you !hould be #ble to t#9e #d?#nt#ge o' *#cro! only 6hen 6riting 'unction!. &he <ob o' *#cro! i! to #b!tr#ct #6#y co**on !ynt#ctic p#ttern!, #nd cert#in p#ttern! co*e up #g#in #nd #g#in in 6riting *#cro! th#t c#n #l!o bene'it 'ro* being #b!tr#cted #6#y. In '#ct, you@?e #lre#dy !een one !uch p#ttern--*#ny *#cro! 6ill, li9e the l#!t ?er!ion o' do-primes, !t#rt 6ith # LET th#t introduce! # 'e6 ?#ri#ble! holding gen!y*ed !y*bol! to be u!ed in the *#cro@! e.p#n!ion. Since thi! i! !uch # co**on p#ttern, 6hy not #b!tr#ct it #6#y 6ith it! o6n *#cro" In thi! !ection you@ll 6rite # *#cro, with-gens?ms, th#t doe! <u!t th#t. In other 6ord!, you@ll 6rite # *#cro-6riting *#cro: # *#cro th#t gener#te! code th#t gener#te! code. While co*ple. *#cro-6riting *#cro! c#n be # bit con'u!ing until you get u!ed to 9eeping the ?#riou! le?el! o' code cle#r in your *ind, with-gens?ms i! '#irly !tr#ight'or6#rd #nd 6ill !er?e #! # u!e'ul but not too !trenuou! *ent#l
#nd h#?e it be eFui?#lent to the pre?iou! ?er!ion o' do-primes. In other 6ord!, the withgens?ms need! to e.p#nd into # LET th#t bind! e#ch n#*ed ?#ri#ble, ending-val'e-name in thi! c#!e, to # gen!y*ed !y*bol. &h#t@! e#!y enough to 6rite 6ith # !i*ple b#c9Fuote te*pl#te.
1de(macro#with-gens?ms#11>rest#names3#>bod?#bod?3 ##B1let#51loop#(or#n#in#names#collect#B15n#1gens?m333 #####5Pbod?33
:ote ho6 you c#n u!e # co**# to interpol#te the ?#lue o' the LOOP e.pre!!ion. &he loop gener#te! # li!t o' binding 'or*! 6here e#ch binding 'or* con!i!t! o' # li!t cont#ining one o' the n#*e! gi?en to with-gens?ms #nd the liter#l code 1gens?m3. 4ou c#n te!t 6h#t code the LOOP e.pre!!ion 6ould gener#te #t the $(P by repl#cing names 6ith # li!t o' !y*bol!.
$L-+,-./#1loop#(or#n#in#C1a#b#c3#collect#B15n#1gens?m333 11I#1J-8,H%33#1L#1J-8,H%33#1$#1J-8,H%333
%'ter the li!t o' binding 'or*!, the body #rgu*ent to with-gens?ms i! !pliced in #! the body o' the LET. &hu!, in the code you 6r#p in # with-gens?ms you c#n re'er to #ny o' the ?#ri#ble! n#*ed in the li!t o' ?#ri#ble! p#!!ed to with-gens?ms. I' you *#cro-e.p#nd the with-gens?ms 'or* in the ne6 de'inition o' do-primes, you !hould !ee !o*ething li9e thi!:
1let#11ending-val'e-name#1gens?m333 ##B1do#115var#1ne)t-prime#5start3#1ne)t-prime#102#5var333 ########15ending-val'e-name#5end33 #######11/#5var#5ending-val'e-name33 #####5Pbod?33
oo9! good. While thi! *#cro i! '#irly tri?i#l, it@! i*port#nt to 9eep cle#r #bout 6hen the di''erent *#cro! #re e.p#nded: 6hen you co*pile the DEFMACRO o' do-primes, the with-gens?ms 'or* i! e.p#nded into the code <u!t !ho6n #nd co*piled. &hu!, the co*piled ?er!ion o' do-primes i! <u!t the !#*e #! i' you h#d 6ritten the outer LET by h#nd. When you co*pile # 'unction th#t u!e! doprimes, the code generated by with-gens?ms run! gener#ting the do-primes e.p#n!ion, but with-gens?ms it!el' i!n@t needed to co*pile # do-primes 'or* !ince it h#! #lre#dy been e.p#nded, b#c9 6hen do-primes 6#! co*piled. %nother cl#!!ic *#cro-6riting 3%C$5: 5:C(-5: 4 %nother cl#!!ic *#cro-6riting *#cro i! once-onl?, 6hich i! u!ed to gener#te code th#t e?#lu#te! cert#in *#cro #rgu*ent! once only #nd in # p#rticul#r order. 8!ing once-onl?, you could 6rite doprimes #l*o!t #! !i*ply #! the origin#l le#9y ?er!ion, li9e thi!:
1de(macro#do-primes#11var#start#end3#>bod?#bod?3 ##1once-onl?#1start#end3
>o6e?er, the i*ple*ent#tion o' once-onl? i! # bit too in?ol?ed 'or # blo6-by-blo6 e.pl#n#tion, #! it relie! on *ultiple le?el! o' b#c9Fuoting #nd unFuoting. I' you re#lly 6#nt to !h#rpen your *#cro chop!, you c#n try to 'igure out ho6 it 6or9!. It loo9! li9e thi!:
1de(macro#once-onl?#11>rest#names3#>bod?#bod?3 ##1let#11gens?ms#1loop#(or#n#in#names#collect#1gens?m3333 ####B1let#15P1loop#(or#g#in#gens?ms#collect#B15g#1gens?m3333 ######B1let#155P1loop#(or#g#in#gens?ms#(or#n#in#names#collect#BB155g#55n333 ########51let#15P1loop#(or#n#in#names#(or#g#in#gens?ms#collect#B15n#5g333 ###########5Pbod?33333
6ith 'unction!, *#cro! c#n #l!o cont#in decl#r#tion!, but you don@t need to 6orry #bout tho!e 'or no6.
2APPEND, 3%nother
6hich I h#?en@t di!cu!!ed yet, i! # 'unction th#t t#9e! #ny nu*ber o' li!t #rgu*ent! #nd return! the re!ult o' !plicing the* together into # !ingle li!t. 'unction, MACROEXPAND, 9eep! e.p#nding the re!ult #! long #! the 'ir!t ele*ent o' the re!ulting e.p#n!ion i! the n#*e o' the *#cro. >o6e?er, thi! 6ill o'ten !ho6 you # *uch lo6er-le?el ?ie6 o' 6h#t the code i! doing th#n you 6#nt, !ince b#!ic control con!truct! !uch #! DO #re #l!o i*ple*ented #! *#cro!. In other 6ord!, 6hile it c#n be educ#tion#l to !ee 6h#t your *#cro ulti*#tely e.p#nd! into, it i!n@t # ?ery u!e'ul ?ie6 into 6h#t your o6n *#cro! #re doing.
-I'
the *#cro e.p#n!ion i! !ho6n #ll on one line, it@! prob#bly bec#u!e the ?#ri#ble *PRINTPRETTY* i! NIL. I' it i!, e?#lu#ting 1set(#Uprint-prett?U#t3 !hould *#9e the *#cro e.p#n!ion e#!ier to re#d.
5&hi!
i! 'ro* Joel on -oftware by Doel Spol!9y, #l!o #?#il#ble #t http://www.joelonso(tware.com/#articles/Lea&?Ibstractions.html. Spol!9y@! point in the e!!#y i! th#t #ll #b!tr#ction! le#9 to !o*e e.tentG th#t i!, there #re no per'ect #b!tr#ction!. 7ut th#t doe!n@t *e#n you !hould toler#te le#9! you c#n e#!ily plug.
05' 2It
cour!e, cert#in 'or*! #re !uppo!ed to be e?#lu#ted *ore th#n once, !uch #! the 'or*! in the body o' # do-primes loop. *#y not be ob?iou! th#t thi! loop i! nece!!#rily in'inite gi?en the nonuni'or* occurrence! o' pri*e nu*ber!. &he !t#rting point 'or # proo' th#t it i! in '#ct in'inite i! 7ertr#nd@! po!tul#te, 6hich !#y! 'or #ny n V 1, there e.i!t! # pri*e p, n X p X 5n. /ro* there you c#n pro?e th#t 'or #ny pri*e nu*ber, P le!! th#n the !u* o' the preceding pri*e nu*ber!, the ne.t pri*e, P@, i! #l!o !*#ller th#n the origin#l
!u* plu! P.
/unction! th#t h#?e !ide e''ect! 6ill be te!ted !lightly di''erently--you@ll h#?e to c#ll the 'unction #nd then chec9 'or e?idence o' the e.pected !ide e''ect!.2 7ut in the end, e?ery te!t c#!e h#! to boil do6n to # boole#n e.pre!!ion, thu*b! up or thu*b! do6n.
Whene?er you 6#nt to run thi! !et o' te!t c#!e!, you c#n c#ll test-2.
$L-+,-./#1test-23 F
%! long #! it return! T, you 9no6 the te!t c#!e! #re p#!!ing. &hi! 6#y o' org#niAing te!t! i! #l!o ple#!#ntly conci!e--you don@t h#?e to 6rite # bunch o' te!t boo99eeping code. >o6e?er, #! you@ll di!co?er the 'ir!t ti*e # te!t c#!e '#il!, the re!ult reporting le#?e! !o*ething to be de!ired. When test-2 return! NIL, you@ll 9no6 !o*ething '#iled, but you@ll h#?e no ide# 6hich te!t c#!e it 6#!. So let@! try #nother !i*ple--e?en !i*ple*inded--#ppro#ch. &o 'ind out 6h#t h#ppen! to e#ch te!t c#!e, you could 6rite !o*ething li9e thi!:
1de('n#test-2#13 ##1(ormat#t#47:DEI9L7Spass7G#...#7a764#1=#12#0#!3#33#C1=#12#0#!3#333 ##1(ormat#t#47:DEI9L7Spass7G#...#7a764#1=#12#0#!#33#63#C1=#12#0#!#33#633 ##1(ormat#t#47:DEI9L7Spass7G#...#7a764#1=#12#-0#-33#-43#C1=#12#-0#-33#-4333
:o6 e#ch te!t c#!e 6ill be reported indi?idu#lly. &he 7:DEI9L7Spass7G p#rt o' the FORMAT directi?e c#u!e! FORMAT to print H/%I H i' the 'ir!t 'or*#t #rgu*ent i! '#l!e #nd Hp#!!H other6i!e.3 &hen you l#bel the re!ult 6ith the te!t e.pre!!ion it!el'. :o6 running test-2 !ho6! you e.#ctly 6h#t@! going on.
$L-+,-./#1test-23 pass#...#1=#12#0#!3#33 pass#...#1=#12#0#!#33#63 pass#...#1=#12#-0#-33#-43 89L
&hi! ti*e the re!ult reporting i! *ore li9e 6h#t you 6#nt, but the code it!el' i! pretty gro!!. &he repe#ted c#ll! to FORMAT #! 6ell #! the tediou! duplic#tion o' the te!t e.pre!!ion cry out to be re'#ctored. &he duplic#tion o' the te!t e.pre!!ion i! p#rticul#rly gr#ting bec#u!e i' you *i!type it, the te!t re!ult! 6ill be *i!l#beled.
%nother proble* i! th#t you don@t get # !ingle indic#tor 6hether #ll the te!t c#!e! p#!!ed. It@! e#!y enough, 6ith only three te!t c#!e!, to !c#n the output loo9ing 'or H/%I HG ho6e?er, 6hen you h#?e hundred! o' te!t c#!e!, it@ll be *ore o' # h#!!le.
Re actoring
Wh#t you@d re#lly li9e i! # 6#y to 6rite te!t 'unction! #! !tre#*lined #! the 'ir!t test-2 th#t return # !ingle T or NIL ?#lue but th#t #l!o report on the re!ult! o' indi?idu#l te!t c#!e! li9e the !econd ?er!ion. Since the !econd ?er!ion i! clo!e to 6h#t you 6#nt in ter*! o' 'unction#lity, your be!t bet i! to !ee i' you c#n '#ctor out !o*e o' the #nnoying duplic#tion. &he !i*ple!t 6#y to get rid o' the repe#ted !i*il#r c#ll! to FORMAT i! to cre#te # ne6 'unction.
1de('n#report-res'lt#1res'lt#(orm3 ##1(ormat#t#47:DEI9L7Spass7G#...#7a764#res'lt#(orm33
:o6 you c#n 6rite test-2 6ith c#ll! to report-res'lt in!te#d o' FORMAT. It@! not # huge i*pro?e*ent, but #t le#!t no6 i' you decide to ch#nge the 6#y you report re!ult!, there@! only one pl#ce you h#?e to ch#nge.
1de('n#test-2#13 ##1report-res'lt#1=#12#0#!3#33#C1=#12#0#!3#333 ##1report-res'lt#1=#12#0#!#33#63#C1=#12#0#!#33#633 ##1report-res'lt#1=#12#-0#-33#-43#C1=#12#-0#-33#-4333
:e.t you need to get rid o' the duplic#tion o' the te!t c#!e e.pre!!ion, 6ith it! #ttend#nt ri!9 o' *i!l#beling o' re!ult!. Wh#t you@d re#lly li9e i! to be #ble to tre#t the e.pre!!ion #! both code Bto get the re!ultC #nd d#t# Bto u!e #! the l#belC. Whene?er you 6#nt to tre#t code #! d#t#, th#t@! # !ure !ign you need # *#cro. 5r, to loo9 #t it #nother 6#y, 6h#t you need i! # 6#y to #uto*#te 6riting the error-prone report-res'lt c#ll!. 4ou@d li9e to be #ble to !#y !o*ething li9e thi!:
1chec=#12#0#!3#333
Since you@re on the hunt 'or duplic#tion, 6hy not get rid o' tho!e repe#ted c#ll! to chec&" 4ou c#n de'ine chec& to t#9e #n #rbitr#ry nu*ber o' 'or*! #nd 6r#p the* e#ch in # c#ll to reportres'lt.
1de(macro#chec>bod?#(orms3 ##B1progn
#####5P1loop#(or#(#in#(orms#collect#B1report-res'lt#5(#C5(3333
&hi! de'inition u!e! # co**on *#cro idio* o' 6r#pping # PROGN #round # !erie! o' 'or*! in order to turn the* into # !ingle 'or*. :otice #l!o ho6 you c#n u!e 5P to !plice in the re!ult o' #n e.pre!!ion th#t return! # li!t o' e.pre!!ion! th#t #re the*!el?e! gener#ted 6ith # b#c9Fuote te*pl#te. With the ne6 ?er!ion o' chec& you c#n 6rite # ne6 ?er!ion o' test-2 li9e thi!:
1de('n#test-2#13 ##1chec& ####1=#12#0#!3#33 ####1=#12#0#!#33#63 ####1=#12#-0#-33#-4333
&h#n9! to chec&, thi! ?er!ion i! #! conci!e #! the 'ir!t ?er!ion o' test-2 but e.p#nd! into code th#t doe! the !#*e thing #! the !econd ?er!ion. %nd no6 #ny ch#nge! you 6#nt to *#9e to ho6 test-2 beh#?e!, you c#n *#9e by ch#nging chec&.
:o6 th#t report-res'lt return! the re!ult o' it! te!t c#!e, it *ight !ee* you could <u!t ch#nge the PROGN to #n AND to co*bine the re!ult!. 8n'ortun#tely, AND doe!n@t do Fuite 6h#t you 6#nt in thi! c#!e bec#u!e o' it! !hort-circuiting beh#?ior: #! !oon #! one te!t c#!e '#il!, AND 6ill !9ip the re!t. 5n the other h#nd, i' you h#d # con!truct th#t 6or9ed li9e AND 6ithout the !hort-circuiting, you could u!e it in the pl#ce o' PROGN, #nd you@d be done. Co**on i!p doe!n@t pro?ide !uch # con!truct, but th#t@! no re#!on you c#n@t u!e it: it@! # tri?i#l *#tter to 6rite # *#cro to pro?ide it your!el'. e#?ing te!t c#!e! #!ide 'or # *o*ent, 6h#t you 6#nt i! # *#cro--let@! c#ll it combine-res'lts-th#t 6ill let you !#y thi!:
1combine-res'lts ##1(oo3 ##1bar3 ##1ba*33
&he only tric9y bit to 6riting thi! *#cro i! th#t you need to introduce # ?#ri#ble--res'lt in the pre?iou! code--in the e.p#n!ion. %! you !#6 in the pre?iou! ch#pter, u!ing # liter#l n#*e 'or ?#ri#ble! in *#cro e.p#n!ion! c#n introduce # le#9 in your *#cro #b!tr#ction, !o you@ll need to cre#te # uniFue n#*e. &hi! i! # <ob 'or with-gens?ms. 4ou c#n de'ine combine-res'lts li9e thi!:
1de(macro#combine-res'lts#1>bod?#(orms3 ##1with-gens?ms#1res'lt3 ####B1let#115res'lt#t33 ######5P1loop#(or#(#in#(orms#collect#B1'nless#5(#1set(#5res'lt#nil333 ######5res'lt333
:o6 you c#n 'i. chec& by !i*ply ch#nging the e.p#n!ion to u!e combine-res'lts in!te#d o' PROGN.
1de(macro#chec>bod?#(orms3 ##B1combine-res'lts ####5P1loop#(or#(#in#(orms#collect#B1report-res'lt#5(#C5(3333
With th#t ?er!ion o' chec&, test-2 !hould e*it the re!ult! o' it! three te!t e.pre!!ion! #nd then return T to indic#te th#t e?erything p#!!ed.$L-+,-./#1test-23 pass#...#1=#12#0#!3#33 pass#...#1=#12#0#!#33#63 pass#...#1=#12#-0#-33#-43 F
%nd i' you ch#nge one o' the te!t c#!e! !o it '#il!,5 the 'in#l return ?#lue ch#nge! to NIL.
$L-+,-./#1test-23 pass#...#1=#12#0#!3#33 pass#...#1=#12#0#!#33#63 EI9L#...#1=#12#-0#-33#-"3 89L
:o6 th#t you h#?e t6o te!t 'unction!, you@ll prob#bly 6#nt #nother 'unction th#t run! #ll the te!t!. &h#t@! e#!y enough.
1de('n#test-arithmetic#13 ##1combine-res'lts ###1test-23 ###1test-U333
In thi! 'unction you u!e combine-res'lts in!te#d o' chec& !ince both test-2 #nd test-U 6ill t#9e c#re o' reporting their o6n re!ult!. When you run test-arithmetic, you@ll get the 'ollo6ing re!ult!:
$L-+,-./#1test-arithmetic3 pass#...#1=#12#0#!3#33 pass#...#1=#12#0#!#33#63 pass#...#1=#12#-0#-33#-43 pass#...#1=#1U#!#!3#43 pass#...#1=#1U#3#"3#0"3 F
:o6 i*#gine th#t one o' the te!t c#!e! '#iled #nd you need to tr#c9 do6n the proble*. With only 'i?e te!t c#!e! #nd t6o te!t 'unction!, it 6on@t be too h#rd to 'ind the code o' the '#iling te!t c#!e. 7ut !uppo!e you h#d 500 te!t c#!e! !pre#d #cro!! 20 'unction!. It *ight be nice i' the re!ult! told you 6h#t 'unction e#ch te!t c#!e c#*e 'ro*. Since the code th#t print! the re!ult! i! centr#liAed in report-res'lt, you need # 6#y to p#!! in'or*#tion #bout 6h#t te!t 'unction you@re in to report-res'lt. 4ou could #dd # p#r#*eter to report-res'lt to p#!! thi! in'or*#tion, but chec&, 6hich gener#te! the c#ll! to reportres'lt, doe!n@t 9no6 6h#t 'unction it@! being c#lled 'ro*, 6hich *e#n! you@d #l!o h#?e to ch#nge the 6#y you c#ll chec&, p#!!ing it #n #rgu*ent th#t it !i*ply p#!!e! onto report-res'lt. &hi! i! e.#ctly the 9ind o' proble* dyn#*ic ?#ri#ble! 6ere de!igned to !ol?e. I' you cre#te # dyn#*ic ?#ri#ble th#t e#ch te!t 'unction bind! to the n#*e o' the 'unction be'ore c#lling chec&, then reportres'lt c#n u!e it 6ithout chec& h#?ing to 9no6 #nything #bout it. Step one i! to decl#re the ?#ri#ble #t the top le?el.
1de(var#Utest-nameU#nil3
:o6 you need to *#9e #nother tiny ch#nge to report-res'lt to include Utest-nameU in the FORMAT output.
1(ormat#t#47:DEI9L7Spass7G#...#7a:#7a764#res'lt#Utest-nameU#(orm3
With tho!e ch#nge!, the te!t 'unction! 6ill !till 6or9 but 6ill produce the 'ollo6ing output bec#u!e Utest-nameU i! ne?er rebound:
$L-+,-./#1test-arithmetic3 pass#...#89L:#1=#12#0#!3#33 pass#...#89L:#1=#12#0#!#33#63 pass#...#89L:#1=#12#-0#-33#-43 pass#...#89L:#1=#1U#!#!3#43 pass#...#89L:#1=#1U#3#"3#0"3 F
/or the n#*e to be reported properly, you need to ch#nge the t6o te!t 'unction!.
1de('n#test-2#13 ##1let#11Utest-nameU#Ctest-233 ####1chec& ######1=#12#0#!3#33 ######1=#12#0#!#33#63 ######1=#12#-0#-33#-43333 1de('n#test-U#13 ##1let#11Utest-nameU#Ctest-U33 ####1chec& ######1=#1U#!#!3#43 ######1=#1U#3#"3#0"3333
An A2straction !$erges
In 'i.ing the te!t 'unction!, you@?e introduced !e?er#l ne6 bit! o' duplic#tion. :ot only doe! e#ch 'unction h#?e to include the n#*e o' the 'unction t6ice--once #! the n#*e in the DEFUN #nd once in the binding o' Utest-nameU--but the !#*e three-line code p#ttern i! duplic#ted bet6een the t6o 'unction!. 4ou could re*o?e the duplic#tion !i*ply on the ground! th#t duplic#tion i! b#d. 7ut i' you loo9 *ore clo!ely #t the root c#u!e o' the duplic#tion, you c#n le#rn #n i*port#nt le!!on #bout ho6 to u!e *#cro!. &he re#!on both the!e 'unction! !t#rt the !#*e 6#y i! bec#u!e they@re both te!t 'unction!. &he duplic#tion #ri!e! bec#u!e, #t the *o*ent, test function i! only h#l' #n #b!tr#ction. &he #b!tr#ction e.i!t! in your *ind, but in the code there@! no 6#y to e.pre!! Hthi! i! # te!t 'unctionH other th#n to 6rite code th#t 'ollo6! # p#rticul#r p#ttern. 8n'ortun#tely, p#rti#l #b!tr#ction! #re # cru**y tool 'or building !o't6#re. 7ec#u!e # h#l' #b!tr#ction i! e.pre!!ed in code by # *#ni'e!t#tion o' the p#ttern, you@re gu#r#nteed to h#?e *#!!i?e code duplic#tion 6ith #ll the nor*#l b#d con!eFuence! th#t i*plie! 'or *#int#in#bility. 3ore !ubtly, bec#u!e the #b!tr#ction e.i!t! only in the *ind! o' progr#**er!, there@! no *ech#ni!* to *#9e !ure di''erent progr#**er! Bor e?en the !#*e progr#**er 6or9ing #t di''erent ti*e!C #ctu#lly under!t#nd the #b!tr#ction the !#*e 6#y. &o *#9e # co*plete #b!tr#ction, you need # 6#y to e.pre!! Hthi! i! # te!t 'unctionH #nd h#?e #ll the code reFuired by the p#ttern be gener#ted 'or you. In other 6ord!, you need # *#cro. 7ec#u!e the p#ttern you@re trying to c#pture i! # DEFUN plu! !o*e boilerpl#te code, you need to 6rite # *#cro th#t 6ill e.p#nd into # DEFUN. 4ou@ll then u!e thi! *#cro, in!te#d o' # pl#in DEFUN to de'ine te!t 'unction!, !o it *#9e! !en!e to c#ll it de(test.
1de(macro#de(test#1name#parameters#>bod?#bod?3 ##B1de('n#5name#5parameters ####1let#11Utest-nameU#C5name33 ######5Pbod?333
A .ierarchy o Tests
:o6 th#t you@?e e!t#bli!hed te!t 'unction! #! 'ir!t-cl#!! citiAen!, the Fue!tion *ight #ri!e, !hould test-arithmetic be # te!t 'unction" %! thing! !t#nd, it doe!n@t re#lly *#tter--i' you did de'ine it 6ith de(test, it! binding o' Utest-nameU 6ould be !h#do6ed by the binding! in test-2 #nd test-U be'ore #ny re!ult! #re reported. 7ut no6 i*#gine you@?e got thou!#nd! o' te!t c#!e! to org#niAe. &he 'ir!t le?el o' org#niA#tion i! pro?ided by te!t 'unction! !uch #! test-2 #nd test-U th#t directly c#ll chec&. 7ut 6ith thou!#nd! o' te!t c#!e!, you@ll li9ely need other le?el! o' org#niA#tion. /unction! !uch #! test-arithmetic c#n group rel#ted te!t 'unction! into te!t !uite!. :o6 !uppo!e !o*e lo6-le?el te!t 'unction! #re c#lled 'ro* *ultiple te!t !uite!. It@! not unhe#rd o' 'or # te!t c#!e to p#!! in one conte.t but '#il in #nother. I' th#t h#ppen!, you@ll prob#bly 6#nt to 9no6 *ore th#n <u!t 6h#t lo6-le?el te!t 'unction cont#in! the te!t c#!e. I' you de'ine the te!t !uite 'unction! !uch #! test-arithmetic 6ith de(test #nd *#9e # !*#ll ch#nge to the Utest-nameU boo99eeping, you c#n h#?e re!ult! reported 6ith # H'ully Fu#li'iedH p#th to the te!t c#!e, !o*ething li9e thi!:
pass#...#1F-,F-I.9F:%-F9$#F-,F-23:#1=#12#0#!3#33
7ec#u!e you@?e #lre#dy #b!tr#cted the proce!! o' de'ining # te!t 'unction, you c#n ch#nge the boo99eeping det#il! 6ithout *odi'ying the code o' the te!t 'unction!.0 &o *#9e Utest-nameU hold # li!t o' te!t 'unction n#*e! in!te#d o' <u!t the n#*e o' the *o!t recently entered te!t 'unction, you <u!t need to ch#nge thi! binding 'or*:
1let#11Utest-nameU#C5name33
to the 'ollo6ing:
1let#11Utest-nameU#1append#Utest-nameU#1list#C5name3333
Since APPEND return! # ne6 li!t *#de up o' the ele*ent! o' it! #rgu*ent!, thi! ?er!ion 6ill bind Utest-nameU to # li!t cont#ining the old content! o' Utest-nameU 6ith the ne6 n#*e t#c9ed onto the end.2 When e#ch te!t 'unction return!, the old ?#lue o' Utest-nameU 6ill be re!tored. :o6 you c#n rede'ine test-arithmetic 6ith de(test in!te#d o' DEFUN.
1de(test#test-arithmetic#13 ##1combine-res'lts ###1test-23 ###1test-U333
&he re!ult! no6 !ho6 e.#ctly ho6 you got to e#ch te!t e.pre!!ion.
$L-+,-./#1test-arithmetic3 pass#...#1F-,F-I.9F:%-F9$#F-,F-23:#1=#12#0#!3#33
%! your te!t !uite gro6!, you c#n #dd ne6 l#yer! o' te!t 'unction!G #! long #! they@re de'ined 6ith de(test, the re!ult! 6ill be reported correctly. /or in!t#nce, the 'ollo6ing:
1de(test#test-math#13 ##1test-arithmetic33
Wrapping 'p
4ou could 9eep going, #dding *ore 'e#ture! to thi! te!t 'r#*e6or9. 7ut #! # 'r#*e6or9 'or 6riting te!t! 6ith # *ini*u* o' bu!y6or9 #nd e#!ily running the* 'ro* the $(P , thi! i! # re#!on#ble !t#rt. >ere@! the co*plete code, #ll 20 line! o' it:
1de(var#Utest-nameU#nil3 1de(macro#de(test#1name#parameters#>bod?#bod?3 ##4<e(ine#a#test#('nction.#Within#a#test#('nction#we#can#call ###other#test#('nctions#or#'se#Cchec&C#to#r'n#individ'al#test ###cases.4 ##B1de('n#5name#5parameters ####1let#11Utest-nameU#1append#Utest-nameU#1list#C5name3333 ######5Pbod?333 1de(macro#chec>bod?#(orms3 ##4.'n#each#e)pression#in#C(ormsC#as#a#test#case.4 ##B1combine-res'lts ####5P1loop#(or#(#in#(orms#collect#B1report-res'lt#5(#C5(3333 1de(macro#combine-res'lts#1>bod?#(orms3 ##4$ombine#the#res'lts#1as#booleans3#o(#eval'ating#C(ormsC#in#order.4 ##1with-gens?ms#1res'lt3 ####B1let#115res'lt#t33 ######5P1loop#(or#(#in#(orms#collect#B1'nless#5(#1set(#5res'lt#nil333 ######5res'lt333 1de('n#report-res'lt#1res'lt#(orm3 ##4.eport#the#res'lts#o(#a#single#test#case.#$alled#b?#Cchec&C.4 ##1(ormat#t#47:DEI9L7Spass7G#...#7a:#7a764#res'lt#Utest-nameU#(orm3 ##res'lt3
It@! 6orth re?ie6ing ho6 you got here bec#u!e it@! illu!tr#ti?e o' ho6 progr#**ing in i!p o'ten goe!.
4ou !t#rted by de'ining # !i*ple ?er!ion o' your proble*--ho6 to e?#lu#te # bunch o' boole#n e.pre!!ion! #nd 'ind out i' they #ll returned true. Du!t ANDing the* together 6or9ed #nd 6#! !ynt#ctic#lly cle#n but re?e#led the need 'or better re!ult reporting. So you 6rote !o*e re#lly !i*ple*inded code, choc9-'ull o' duplic#tion #nd error-prone idio*! th#t reported the re!ult! the 6#y you 6#nted. &he ne.t !tep 6#! to !ee i' you could re'#ctor the !econd ?er!ion into !o*ething #! cle#n #! the 'or*er. 4ou !t#rted 6ith # !t#nd#rd re'#ctoring techniFue o' e.tr#cting !o*e code into # 'unction, reportres'lt. 8n'ortun#tely, you could !ee th#t u!ing report-res'lt 6#! going to be tediou! #nd error-prone !ince you h#d to p#!! the te!t e.pre!!ion t6ice, once 'or the ?#lue #nd once #! Fuoted d#t#. So you 6rote the chec& *#cro to #uto*#te the det#il! o' c#lling report-res'lt correctly. While 6riting chec&, you re#liAed #! long #! you 6ere gener#ting code, you could *#9e # !ingle c#ll to chec& to gener#te *ultiple c#ll! to report-res'lt, getting you b#c9 to # ?er!ion o' test-2 #bout #! conci!e #! the origin#l AND ?er!ion. %t th#t point you h#d the chec& %PI n#iled do6n, 6hich #llo6ed you to !t#rt *uc9ing 6ith ho6 it 6or9ed on the in!ide. &he ne.t t#!9 6#! to 'i. chec& !o the code it gener#ted 6ould return # boole#n indic#ting 6hether #ll the te!t c#!e! h#d p#!!ed. $#ther th#n i**edi#tely h#c9ing #6#y #t chec&, you p#u!ed to indulge in # little l#ngu#ge de!ign by '#nt#!y. Wh#t i'--you '#nt#!iAed--there 6#! #lre#dy # non-!hort-circuiting AND con!truct. &hen 'i.ing chec& 6ould be tri?i#l. $eturning 'ro* '#nt#!yl#nd you re#liAed there 6#! no !uch con!truct but th#t you could 6rite one in # 'e6 line!. %'ter 6riting combine-res'lts, the 'i. to chec& 6#! indeed tri?i#l. %t th#t point #ll th#t 6#! le't 6#! to *#9e # 'e6 *ore i*pro?e*ent! to the 6#y you reported te!t re!ult!. 5nce you !t#rted *#9ing ch#nge! to the te!t 'unction!, you re#liAed tho!e 'unction! repre!ented # !peci#l c#tegory o' 'unction th#t de!er?ed it! o6n #b!tr#ction. So you 6rote de(test to #b!tr#ct the p#ttern o' code th#t turn! # regul#r 'unction into # te!t 'unction. With de(test pro?iding #n #b!tr#ction b#rrier bet6een the te!t de'inition! #nd the underlying *#chinery, you 6ere #ble to enh#nce the re!ult reporting 6ithout touching the te!t 'unction!. :o6, 6ith the b#!ic! o' 'unction!, ?#ri#ble!, #nd *#cro! *#!tered, #nd # little pr#ctic#l e.perience u!ing the*, you@re re#dy to !t#rt e.ploring Co**on i!p@! rich !t#nd#rd libr#ry o' 'unction! #nd d#t# type!.
1&hi!
i! 'or illu!tr#ti?e purpo!e! only--ob?iou!ly, 6riting te!t c#!e! 'or built-in 'unction! !uch #! + i! # bit !illy, !ince i' !uch b#!ic thing! #ren@t 6or9ing, the ch#nce! the te!t! 6ill be running the 6#y you e.pect i! pretty !li*. 5n the other h#nd, *o!t Co**on i!p! #re i*ple*ented l#rgely in Co**on i!p, !o it@! not cr#Ay to i*#gine 6riting te!t !uite! in Co**on i!p to te!t the !t#nd#rd libr#ry 'unction!.
2Side
e''ect! c#n include !uch thing! #! !ign#ling error!G I@ll di!cu!! Co**on i!p@! error h#ndling !y!te* in Ch#pter 1). 4ou *#y, #'ter re#ding th#t ch#pter, 6#nt to thin9 #bout ho6 to incorpor#te te!t! th#t chec9 6hether # 'unction doe! or doe! not !ign#l # p#rticul#r error in cert#in !itu#tion!.
3I@ll -I'
di!cu!! thi! #nd other FORMAT directi?e! in *ore det#il in Ch#pter 1,.
test-2 h#! been co*piled--6hich *#y h#ppen i*plicitly in cert#in i!p i*ple*ent#tion!--you *#y need to ree?#lu#te the de'inition o' test-2 to get the ch#nged de'inition o' chec& to #''ect the beh#?ior o' test-2. Interpreted code, on the other h#nd, typic#lly e.p#nd! *#cro! #ne6 e#ch ti*e the code i! interpreted, #llo6ing the e''ect! o' *#cro rede'inition! to be !een i**edi#tely.
54ou
h#?e to ch#nge the te!t to *#9e it '#il !ince you c#n@t ch#nge the beh#?ior o' +.
0&hough, 2%!
#g#in, i' the te!t 'unction! h#?e been co*piled, you@ll h#?e to reco*pile the* #'ter ch#nging the *#cro. you@ll !ee in Ch#pter 12, APPENDing to the end o' # li!t i!n@t the *o!t e''icient 6#y to build # li!t. 7ut 'or no6 thi! i! !u''icient--#! long #! the te!t hier#rchie! #ren@t too deep, it !hould be 'ine. %nd i' it beco*e! # proble*, #ll you@ll h#?e to do i! ch#nge the de'inition o' de(test.
#! # u!er o' the l#ngu#ge, the built-in d#t# type! #re de'ined by the 'unction! th#t oper#te on the*. So to le#rn # d#t# type, you <u!t h#?e to le#rn #bout the 'unction! you c#n u!e 6ith it. %ddition#lly, *o!t o' the built-in d#t# type! h#?e # !peci#l !ynt#. th#t the i!p re#der under!t#nd! #nd th#t the i!p printer u!e!. &h#t@! 6hy, 'or in!t#nce, you c#n 6rite !tring! #! 4(oo4G nu*ber! #! 0!3, 0/!3, #nd 0.!3G #nd li!t! #! 1a#b#c3. I@ll de!cribe the !ynt#. 'or di''erent 9ind! o' ob<ect! 6hen I de!cribe the 'unction! 'or *#nipul#ting the*. In thi! ch#pter, I@ll co?er the built-in H!c#l#rH d#t# type!: nu*ber!, ch#r#cter!, #nd !tring!. &echnic#lly, !tring! #ren@t true !c#l#r!--# !tring i! # !eFuence o' ch#r#cter!, #nd you c#n #cce!! indi?idu#l ch#r#cter! #nd *#nipul#te !tring! 6ith # 'unction th#t oper#te! on !eFuence!. 7ut I@ll di!cu!! !tring! here bec#u!e *o!t o' the !tring-!peci'ic 'unction! *#nipul#te the* #! !ingle ?#lue! #nd #l!o bec#u!e o' the clo!e rel#tion bet6een !e?er#l o' the !tring 'unction! #nd their ch#r#cter counterp#rt!.
:u$2ers
3#th, #! 7#rbie !#y!, i! h#rd.2 Co**on i!p c#n@t *#9e the *#th p#rt #ny e#!ier, but it doe! tend to get in the 6#y # lot le!! th#n other progr#**ing l#ngu#ge!. &h#t@! not !urpri!ing gi?en it! *#the*#tic#l herit#ge. i!p 6#! origin#lly de!igned by # *#the*#tici#n #! # tool 'or !tudying *#the*#tic#l 'unction!. %nd one o' the *#in pro<ect! o' the 3%C pro<ect #t 3I& 6#! the 3#c!y*# !y*bolic #lgebr# !y!te*, 6ritten in 3#cli!p, one o' Co**on i!p@! i**edi#te predece!!or!. %ddition#lly, i!p h#! been u!ed #! # te#ching l#ngu#ge #t pl#ce! !uch #! 3I& 6here e?en the co*puter !cience pro'e!!or! cringe #t the thought o' telling their !tudent! th#t %789 : 5, le#ding to i!p@! !upport 'or e.#ct r#tio!. %nd #t ?#riou! ti*e! i!p h#! been c#lled upon to co*pete 6ith /5$&$%: in the high-per'or*#nce nu*eric co*puting #ren#. 5ne o' the re#!on! i!p i! # nice l#ngu#ge 'or *#th i! it! nu*ber! beh#?e *ore li9e true *#the*#tic#l nu*ber! th#n the #ppro.i*#tion! o' nu*ber! th#t #re e#!y to i*ple*ent in 'inite co*puter h#rd6#re. /or in!t#nce, integer! in Co**on i!p c#n be #l*o!t #rbitr#rily l#rge r#ther th#n being li*ited by the !iAe o' # *#chine 6ord.3 %nd di?iding t6o integer! re!ult! in #n e.#ct r#tio, not # trunc#ted ?#lue. %nd !ince r#tio! #re repre!ented #! p#ir! o' #rbitr#rily !iAed integer!, r#tio! c#n repre!ent #rbitr#rily preci!e 'r#ction!.5n the other h#nd, 'or high-per'or*#nce nu*eric progr#**ing, you *#y be 6illing to tr#de the e.#ctitude o' r#tion#l! 'or the !peed o''ered by u!ing the h#rd6#re@! underlying 'lo#ting-point oper#tion!. So, Co**on i!p #l!o o''er! !e?er#l type! o' 'lo#ting-point nu*ber!, 6hich #re *#pped by the i*ple*ent#tion to the #ppropri#te h#rd6#re-!upported 'lo#ting-point repre!ent#tion!.5 /lo#t! #re #l!o u!ed to repre!ent the re!ult! o' # co*put#tion 6ho!e true *#the*#tic#l ?#lue 6ould be #n irr#tion#l nu*ber. /in#lly, Co**on i!p !upport! co*ple. nu*ber!--the nu*ber! th#t re!ult 'ro* doing thing! !uch #! t#9ing !Fu#re root! #nd log#rith*! o' neg#ti?e nu*ber!. &he Co**on i!p !t#nd#rd e?en goe! !o '#r #! to !peci'y the princip#l ?#lue! #nd br#nch cut! 'or irr#tion#l #nd tr#n!cendent#l 'unction! on the co*ple. do*#in.
:u$eric Litera%s
4ou c#n 6rite nu*eric liter#l! in # ?#riety o' 6#y!G you !#6 # 'e6 e.#*ple! in Ch#pter -. >o6e?er, it@! i*port#nt to 9eep in *ind the di?i!ion o' l#bor bet6een the i!p re#der #nd the i!p e?#lu#tor--the re#der i! re!pon!ible 'or tr#n!l#ting te.t into i!p ob<ect!, #nd the i!p e?#lu#tor then de#l! only 6ith tho!e ob<ect!. /or # gi?en nu*ber o' # gi?en type, there c#n be *#ny di''erent te.tu#l repre!ent#tion!,
#ll o' 6hich 6ill be tr#n!l#ted to the !#*e ob<ect repre!ent#tion by the i!p re#der. /or in!t#nce, you c#n 6rite the integer 10 #! 0 , ! /!, N)I, or #ny o' # nu*ber o' other 6#y!, but the re#der 6ill tr#n!l#te #ll the!e to the !#*e ob<ect. When nu*ber! #re printed b#c9 out--!#y, #t the $(P --they@re printed in # c#nonic#l te.tu#l !ynt#. th#t *#y be di''erent 'ro* the !ynt#. u!ed to enter the nu*ber. /or e.#*ple:
$L-+,-./#0 0 $L-+,-./#! /! 0 $L-+,-./#N)a 0
&he !ynt#. 'or integer ?#lue! i! #n option#l !ign B2 or -C 'ollo6ed by one or *ore digit!. $#tio! #re 6ritten #! #n option#l !ign #nd # !eFuence o' digit!, repre!enting the nu*er#tor, # !l#!h B/C, #nd #nother !eFuence o' digit! repre!enting the deno*in#tor. %ll r#tion#l nu*ber! #re Hc#nonic#liAedH #! they@re re#d--th#t@! 6hy 0 #nd ! /! #re both re#d #! the !#*e nu*ber, #! #re 3/4 #nd 6/R. $#tion#l! #re printed in HreducedH 'or*--integer ?#lue! #re printed in integer !ynt#. #nd r#tio! 6ith the nu*er#tor #nd deno*in#tor reduced to lo6e!t ter*!. It@! #l!o po!!ible to 6rite r#tion#l! in b#!e! other th#n 10. I' preceded by NL or Nb, # r#tion#l liter#l i! re#d #! # bin#ry nu*ber 6ith #nd 0 #! the only leg#l digit!. %n N; or No indic#te! #n oct#l nu*ber Bleg#l digit! -QC, #nd N[ or N) indic#te! he.#deci*#l Bleg#l digit! -E or -(C. 4ou c#n 6rite r#tion#l! in other b#!e! 'ro* 2 to 30 6ith Nn. 6here n i! the b#!e B#l6#y! 6ritten in deci*#lC. %ddition#l Hdigit!H beyond ) #re t#9en 'ro* the letter! I-^ or a-*. :ote th#t the!e r#di. indic#tor! #pply to the 6hole r#tion#l--it@! not po!!ible to 6rite # r#tio 6ith the nu*er#tor in one b#!e #nd deno*in#tor in #nother. %l!o, you c#n 6rite integer ?#lue!, but not r#tio!, #! deci*#l digit! ter*in#ted 6ith # deci*#l point.0 So*e e.#*ple! o' r#tion#l!, 6ith their c#nonic#l, deci*#l repre!ent#tion #re #! 'ollo6!:
0!3############################==/#0!3 20!3###########################==/#0!3 -0!3###########################==/#-0!3 0!3.###########################==/#0!3 !/3############################==/#!/3 -!/3###########################==/#-!/3 4/6############################==/#!/3 6/3############################==/#! Nb0 0 0########################==/#!0 Nb0 0 /0 00####################==/#0 /00 NoQQQ##########################==/#"00 N)<I<I#########################==/#"6 !6 N36rIL$<-EJ:9_ML%8;TZ.,F+KW[H^#==/#R33Q" 3R"4Q3 40"!40 " 3QQ03"R00!"9!6QR3"
4ou c#n #l!o 6rite 'lo#ting-point nu*ber! in # ?#riety o' 6#y!. 8nli9e r#tion#l nu*ber!, the !ynt#. u!ed to not#te # 'lo#ting-point nu*ber c#n #''ect the #ctu#l type o' nu*ber re#d. Co**on i!p de'ine! 'our !ubtype! o' 'lo#ting-point nu*ber: !hort, !ingle, double, #nd long. (#ch !ubtype c#n u!e # di''erent nu*ber o' bit! in it! repre!ent#tion, 6hich *e#n! e#ch !ubtype c#n repre!ent ?#lue! !p#nning # di''erent r#nge #nd 6ith di''erent preci!ion. 3ore bit! gi?e! # 6ider r#nge #nd *ore preci!ion.2 &he b#!ic 'or*#t 'or 'lo#ting-point nu*ber! i! #n option#l !ign 'ollo6ed by # none*pty !eFuence o' deci*#l digit! po!!ibly 6ith #n e*bedded deci*#l point. &hi! !eFuence c#n be 'ollo6ed by #n e.ponent *#r9er 'or Hco*puteriAed !cienti'ic not#tion.H, &he e.ponent *#r9er con!i!t! o' # !ingle
letter 'ollo6ed by #n option#l !ign #nd # !eFuence o' digit!, 6hich #re interpreted #! the po6er o' ten by 6hich the nu*ber be'ore the e.ponent *#r9er !hould be *ultiplied. &he letter doe! double duty: it *#r9! the beginning o' the e.ponent #nd indic#te! 6h#t 'lo#ting- point repre!ent#tion !hould be u!ed 'or the nu*ber. &he e.ponent *#r9er! s, f, d, l B#nd their upperc#!e eFui?#lent!C indic#te !hort, !ingle, double, #nd long 'lo#t!, re!pecti?ely. &he letter e indic#te! th#t the de'#ult repre!ent#tion Biniti#lly !ingle-'lo#tC !hould be u!ed. :u*ber! 6ith no e.ponent *#r9er #re re#d in the de'#ult repre!ent#tion #nd *u!t cont#in # deci*#l point 'ollo6ed by #t le#!t one digit to di!tingui!h the* 'ro* integer!. &he digit! in # 'lo#ting-point nu*ber #re #l6#y! tre#ted #! b#!e 10 digit!--the NL, N[, N;, #nd N. !ynt#.e! 6or9 only 6ith r#tion#l!. &he 'ollo6ing #re !o*e e.#*ple 'lo#ting-point nu*ber! #long 6ith their c#nonic#l repre!ent#tion:
0. ######==/#0. 0e ######==/#0. 0d ######==/#0. d 0!3. ####==/#0!3. 0!3e ####==/#0!3. .0!3####==/# .0!3 .0!3#####==/# .0!3 0!3e-3###==/# .0!3 0!3--3###==/# .0!3 .0!3e! #==/#0.!3e209 0!3d!3###==/#0.!3d2!"
/in#lly, co*ple. nu*ber! #re 6ritten in their o6n !ynt#., n#*ely, N$ or Nc 'ollo6ed by # li!t o' t6o re#l nu*ber! repre!enting the re#l #nd i*#gin#ry p#rt o' the co*ple. nu*ber. &here #re #ctu#lly 'i?e 9ind! o' co*ple. nu*ber! bec#u!e the re#l #nd i*#gin#ry p#rt! *u!t either both be r#tion#l or both be the !#*e 9ind o' 'lo#ting-point nu*ber. 7ut you c#n 6rite the* ho6e?er you 6#nt--i' # co*ple. i! 6ritten 6ith one r#tion#l #nd one 'lo#tingpoint p#rt, the r#tion#l i! con?erted to # 'lo#t o' the #ppropri#te repre!ent#tion. Si*il#rly, i' the re#l #nd i*#gin#ry p#rt! #re both 'lo#t! o' di''erent repre!ent#tion!, the one in the !*#ller repre!ent#tion 6ill be upgraded. >o6e?er, no co*ple. nu*ber! h#?e # r#tion#l re#l co*ponent #nd # Aero i*#gin#ry p#rt--!ince !uch ?#lue! #re, *#the*#tic#lly !pe#9ing, r#tion#l, they@re repre!ented by the #ppropri#te r#tion#l ?#lue. &he !#*e *#the*#tic#l #rgu*ent could be *#de 'or co*ple. nu*ber! 6ith 'lo#ting-point co*ponent!, but 'or tho!e co*ple. type! # nu*ber 6ith # Aero i*#gin#ry p#rt i! #l6#y! # di''erent ob<ect th#n the 'lo#ting-point nu*ber repre!enting the re#l co*ponent. >ere #re !o*e e.#*ple! o' nu*ber! 6ritten the co*ple. nu*ber !ynt#.:
Nc1!######03####==/#Nc1!#03 Nc1!/3##3/43####==/#Nc1!/3#3/43 Nc1!####0. 3####==/#Nc1!. #0. 3 Nc1!. ##0. d 3##==/#Nc1!. d #0. d 3 Nc10/!##0. 3####==/#Nc1 ."#0. 3 Nc13###### 3####==/#3 Nc13. ## . 3####==/#Nc13. # . 3 Nc10/!#### 3####==/#0/! Nc1-6/3### 3####==/#-!
Basic +ath
&he b#!ic #rith*etic oper#tion!--#ddition, !ubtr#ction, *ultiplic#tion, #nd di?i!ion--#re !upported 'or
#ll the di''erent 9ind! o' i!p nu*ber! 6ith the 'unction! +, -, *, #nd 0. C#lling #ny o' the!e 'unction! 6ith *ore th#n t6o #rgu*ent! i! eFui?#lent to c#lling the !#*e 'unction on the 'ir!t t6o #rgu*ent! #nd then c#lling it #g#in on the re!ulting ?#lue #nd the re!t o' the #rgu*ent!. /or e.#*ple, 12#0#!#33 i! eFui?#lent to 12#12#0#!3#33. With only one #rgu*ent, + #nd * return the ?#lueG - return! it! neg#tion #nd 0 it! reciproc#l.)
12#0#!3##############==/#3 12#0#!#33############==/#6 12#0 . #3. 3#########==/#03. 12#Nc10#!3#Nc13#433##==/#Nc14#63 1-#"#43##############==/#0 1-#!3################==/#-! 1-#0 #3#"3###########==/#! 1U#!#33##############==/#6 1U#!#3#43############==/#!4 1/#0 #"3#############==/#! 1/#0 #"#!3###########==/#0 1/#!#33##############==/#!/3 1/#43################==/#0/4
I' #ll the #rgu*ent! #re the !#*e type o' nu*ber Br#tion#l, 'lo#ting point, or co*ple.C, the re!ult 6ill be the !#*e type e.cept in the c#!e 6here the re!ult o' #n oper#tion on co*ple. nu*ber! 6ith r#tion#l co*ponent! yield! # nu*ber 6ith # Aero i*#gin#ry p#rt, in 6hich c#!e the re!ult 6ill be # r#tion#l. >o6e?er, 'lo#ting-point #nd co*ple. nu*ber! #re contagious--i' #ll the #rgu*ent! #re re#l! but one or *ore #re 'lo#ting-point nu*ber!, the other #rgu*ent! #re con?erted to the ne#re!t 'lo#ting-point ?#lue in # Hl#rge!tH 'lo#ting-point repre!ent#tion o' the #ctu#l 'lo#ting-point #rgu*ent!. /lo#ting-point nu*ber! in # H!*#llerH repre!ent#tion #re #l!o con?erted to the l#rger repre!ent#tion. Si*il#rly, i' #ny o' the #rgu*ent! #re co*ple., #ny re#l #rgu*ent! #re con?erted to the co*ple. eFui?#lent!.
12#0#!. 3#############==/#3. 1/#!#3. 3#############==/# .666666Q 12#Nc10#!3#33#########==/#Nc14#!3 12#Nc10#!3#3/!3#######==/#Nc1"/!#!3 12#Nc10#03#Nc1!#-033##==/#3
7ec#u!e 0 doe!n@t trunc#te, Co**on i!p pro?ide! 'our 'l#?or! o' trunc#ting #nd rounding 'or con?erting # re#l nu*ber Br#tion#l or 'lo#ting pointC to #n integer: FLOOR trunc#te! to6#rd neg#ti?e in'inity, returning the l#rge!t integer le!! th#n or eFu#l to the #rgu*ent. CEILING trunc#te! to6#rd po!iti?e in'inity, returning the !*#lle!t integer gre#ter th#n or eFu#l to the #rgu*ent. TRUNCATE trunc#te! to6#rd Aero, *#9ing it eFui?#lent to FLOOR 'or po!iti?e #rgu*ent! #nd to CEILING 'or neg#ti?e #rgu*ent!. %nd ROUND round! to the ne#re!t integer. I' the #rgu*ent i! e.#ctly h#l'6#y bet6een t6o integer!, it round! to the ne#re!t e?en integer. &6o rel#ted 'unction! #re MOD #nd REM, 6hich return the *odulu! #nd re*#inder o' # trunc#ting di?i!ion on re#l nu*ber!. &he!e t6o 'unction! #re rel#ted to the FLOOR #nd TRUNCATE 'unction! #! 'ollo6!:
12#1U#1(loor####1/#)#?33#?3#1mod#)#?33#===#) 12#1U#1tr'ncate#1/#)#?33#?3#1rem#)#?33#===#)
&hu!, 'or po!iti?e Fuotient! they@re eFui?#lent, but 'or neg#ti?e Fuotient! they produce di''erent re!ult!.10 &he 'unction! 1+ #nd 1- pro?ide # !horth#nd 6#y to e.pre!! #dding #nd !ubtr#cting one 'ro* #
nu*ber. :ote th#t the!e #re di''erent 'ro* the *#cro! INCF #nd DECF. 1+ #nd 1- #re <u!t 'unction! th#t return # ne6 ?#lue, but INCF #nd DECF *odi'y # pl#ce. &he 'ollo6ing eFui?#lence! !ho6 the rel#tion bet6een INCF;DECF, 1+;1-, #nd +;-:
1inc(#)3####===#1set(#)#102#)33#===#1set(#)#12#)#033 1dec(#)3####===#1set(#)#10-#)33#===#1set(#)#1-#)#033 1inc(#)#0 3#===#1set(#)#12#)#0 33 1dec(#)#0 3#===#1set(#)#1-#)#0 33
:u$eric #o$parisons
&he 'unction = i! the nu*eric eFu#lity predic#te. It co*p#re! nu*ber! by *#the*#tic#l ?#lue, ignoring di''erence! in type. &hu!, = 6ill con!ider *#the*#tic#lly eFui?#lent ?#lue! o' di''erent type! eFui?#lent 6hile the generic eFu#lity predic#te EQL 6ould con!ider the* ineFui?#lent bec#u!e o' the di''erence in type. B&he generic eFu#lity predic#te EQUALP, ho6e?er, u!e! = to co*p#re nu*ber!.C I' it@! c#lled 6ith *ore th#n t6o #rgu*ent!, it return! true only i' they #ll h#?e the !#*e ?#lue. &hu!:
1=#0#03########################==/#F 1=#0 #! /!3####################==/#F 1=#0#0. #Nc10. # . 3#Nc10# 33##==/#F
&he 0= 'unction, con?er!ely, return! true only i' all it! #rgu*ent! #re di''erent ?#lue!.
1/=#0#03########==/#89L 1/=#0#!3########==/#F 1/=#0#!#33######==/#F 1/=#0#!#3#03####==/#89L 1/=#0#!#3#0. 3##==/#89L
&he 'unction! 1, 2, 1=, #nd 2= order r#tion#l! #nd 'lo#ting-point nu*ber! Bin other 6ord!, the re#l nu*ber!.C i9e = #nd 0=, the!e 'unction! c#n be c#lled 6ith *ore th#n t6o #rgu*ent!, in 6hich c#!e e#ch #rgu*ent i! co*p#red to the #rgu*ent to it! right.
1O#!#33#######==/#F 1/#!#33#######==/#89L 1/#3#!3#######==/#F 1O#!#3#43#####==/#F 1O#!#3#33#####==/#89L 1O=#!#3#33####==/#F 1O=#!#3#3#43##==/#F 1O=#!#3#4#33##==/#89L
&o pic9 out the !*#lle!t or l#rge!t o' !e?er#l nu*ber!, you c#n u!e the 'unction MIN or MAX, 6hich t#9e! #ny nu*ber o' re#l nu*ber #rgu*ent! #nd return! the *ini*u* or *#.i*u* ?#lue.
1ma)#0 #003####==/#00 1min#-0!#-0 3##==/#-0! 1ma)#-0#!#-33##==/#!
So*e other h#ndy 'unction! #re 3EROP, MINUSP, #nd PLUSP, 6hich te!t 6hether # !ingle re#l nu*ber i! eFu#l to, le!! th#n, or gre#ter th#n Aero. &6o other predic#te!, EVENP #nd ODDP, te!t 6hether # !ingle integer #rgu*ent i! e?en or odd. &he P !u''i. on the n#*e! o' the!e 'unction! i! # !t#nd#rd n#*ing con?ention 'or predic#te 'unction!, 'unction! th#t te!t !o*e condition #nd return # boole#n.
.igher +ath
&he 'unction! you@?e !een !o '#r #re the beginning o' the built-in *#the*#tic#l 'unction!. i!p #l!o !upport! log#rith*!: LOGG e.ponenti#tion: EXP #nd EXPTG the b#!ic trigono*etric 'unction!: SIN, COS, #nd TANG their in?er!e!: ASIN, ACOS, #nd ATANG hyperbolic 'unction!: SINH, COSH, #nd TANHG #nd their in?er!e!: ASINH, ACOSH, #nd ATANH. It #l!o pro?ide! 'unction! to get #t the indi?idu#l bit! o' #n integer #nd to e.tr#ct the p#rt! o' # r#tio or # co*ple. nu*ber. /or # co*plete li!t, !ee #ny Co**on i!p re'erence.
#haracters
Co**on i!p ch#r#cter! #re # di!tinct type o' ob<ect 'ro* nu*ber!. &h#t@! #! it !hould be--ch#r#cter! #re not nu*ber!, #nd l#ngu#ge! th#t tre#t the* #! i' they #re tend to run into proble*! 6hen ch#r#cter encoding! ch#nge, !#y, 'ro* ,-bit %SCII to 21-bit 8nicode.11 7ec#u!e the Co**on i!p !t#nd#rd didn@t *#nd#te # p#rticul#r repre!ent#tion 'or ch#r#cter!, tod#y !e?er#l i!p i*ple*ent#tion! u!e 8nicode #! their Hn#ti?eH ch#r#cter encoding de!pite 8nicode being only # gle#* in # !t#nd#rd! body@! eye #t the ti*e Co**on i!p@! o6n !t#nd#rdiA#tion 6#! being 6r#pped up. &he re#d !ynt#. 'or ch#r#cter! ob<ect! i! !i*ple: NY 'ollo6ed by the de!ired ch#r#cter. &hu!, NY) i! the ch#r#cter ). %ny ch#r#cter c#n be u!ed #'ter the NY, including other6i!e !peci#l ch#r#cter! !uch #! 4, 1, #nd 6hite!p#ce. >o6e?er, 6riting 6hite!p#ce ch#r#cter! thi! 6#y i!n@t ?ery Bhu*#nC re#d#bleG #n #ltern#ti?e !ynt#. 'or cert#in ch#r#cter! i! NY 'ollo6ed by the ch#r#cter@! n#*e. (.#ctly 6h#t n#*e! #re !upported depend! on the ch#r#cter !et #nd on the i!p i*ple*ent#tion, but #ll i*ple*ent#tion! !upport the n#*e! -pace #nd 2ewline. &hu!, you !hould 6rite NY,pace in!te#d o' NY#, though the l#tter i! technic#lly leg#l. 5ther !e*i!t#nd#rd n#*e! Bth#t i*ple*ent#tion! *u!t u!e i' the ch#r#cter !et h#! the #ppropri#te ch#r#cter!C #re Tab, Page, *ubout, Linefeed, *eturn, #nd #ac$space.
#haracter #o$parisons
&he *#in thing you c#n do 6ith ch#r#cter!, other th#n putting the* into !tring! B6hich I@ll get to l#ter in thi! ch#pterC, i! to co*p#re the* 6ith other ch#r#cter!. Since ch#r#cter! #ren@t nu*ber!, you c#n@t u!e the nu*eric co*p#ri!on 'unction!, !uch #! 1 #nd 2. In!te#d, t6o !et! o' 'unction! pro?ide ch#r#cter-!peci'ic #n#log! to the nu*eric co*p#r#tor!G one !et i! c#!e-!en!iti?e #nd the other c#!ein!en!iti?e. &he c#!e-!en!iti?e #n#log to the nu*eric = i! the 'unction CHAR=. i9e =, CHAR= c#n t#9e #ny nu*ber o' #rgu*ent! #nd return! true only i' they@re #ll the !#*e ch#r#cter. &he c#!e- in!en!iti?e ?er!ion i! CHAR-EQUAL. &he re!t o' the ch#r#cter co*p#r#tor! 'ollo6 thi! !#*e n#*ing !che*e: the c#!e-!en!iti?e co*p#r#tor! #re n#*ed by prepending the #n#logou! nu*eric co*p#r#tor 6ith $:I.G the c#!e-in!en!iti?e ?er!ion! !pell out the co*p#r#tor n#*e, !ep#r#ted 'ro* the $:I. 6ith # hyphen. :ote, ho6e?er, th#t O= #nd /= #re H!pelled outH 6ith the logic#l eFui?#lent! NOT-GREATERP #nd NOT-LESSP r#ther th#n the *ore ?erbo!e L-,,T-;.--Z+ILT #nd J.-IF-.T-;.--Z+ILT. i9e their nu*eric counterp#rt!, #ll the!e 'unction! c#n t#9e one or *ore #rgu*ent!. &#ble 10-1 !u**#riAe! the rel#tion bet6een the nu*eric #nd ch#r#cter co*p#ri!on 'unction!. &#ble 10-1. Ch#r#cter Co*p#ri!on /unction! :u$eric Ana%og #ase4/ensiti,e #ase4Insensiti,e
= CHAR= CHAR-EQUAL 0= CHAR0= CHAR-NOT-EQUAL 1 CHAR1 CHAR-LESSP 2 CHAR2 CHAR-GREATERP 1= CHAR1= CHAR-NOT-GREATERP 2= CHAR2= CHAR-NOT-LESSP 5ther 'unction! th#t de#l 6ith ch#r#cter! pro?ide 'unction! 'or, #*ong other thing!, te!ting 6hether # gi?en ch#r#cter i! #lph#betic or # digit ch#r#cter, te!ting the c#!e o' # ch#r#cter, obt#ining # corre!ponding ch#r#cter in # di''erent c#!e, #nd tr#n!l#ting bet6een nu*eric ?#lue! repre!enting ch#r#cter code! #nd #ctu#l ch#r#cter ob<ect!. %g#in, 'or co*plete det#il!, !ee your '#?orite Co**on i!p re'erence.
/trings
%! *entioned e#rlier, !tring! in Co**on i!p #re re#lly # co*po!ite d#t# type, n#*ely, # onedi*en!ion#l #rr#y o' ch#r#cter!. Con!eFuently, I@ll co?er *#ny o' the thing! you c#n do 6ith !tring! in the ne.t ch#pter 6hen I di!cu!! the *#ny 'unction! 'or *#nipul#ting !eFuence!, o' 6hich !tring! #re <u!t one type. 7ut !tring! #l!o h#?e their o6n liter#l !ynt#. #nd # libr#ry o' 'unction! 'or per'or*ing !tring-!peci'ic oper#tion!. I@ll di!cu!! the!e #!pect! o' !tring! in thi! ch#pter #nd le#?e the other! 'or Ch#pter 11. %! you@?e !een, liter#l !tring! #re 6ritten enclo!ed in double Fuote!. 4ou c#n include #ny ch#r#cter !upported by the ch#r#cter !et in # liter#l !tring e.cept double Fuote B4C #nd b#c9!l#!h BYC. %nd you c#n include the!e t6o #! 6ell i' you e!c#pe the* 6ith # b#c9!l#!h. In '#ct, b#c9!l#!h #l6#y! e!c#pe! the ne.t ch#r#cter, 6h#te?er it i!, though thi! i!n@t nece!!#ry 'or #ny ch#r#cter e.cept 'or 4 #nd it!el'. &#ble 10-2 !ho6! ho6 ?#riou! liter#l !tring! 6ill be re#d by the i!p re#der. &#ble 10-2. iter#l String! Litera% #ontents #o$$ent 4(oobar4 'oob#r Pl#in !tring. 4(ooY4bar4 'ooHb#r &he b#c9!l#!h e!c#pe! Fuote. 4(ooYYbar4 'ooYb#r &he 'ir!t b#c9!l#!h e!c#pe! !econd b#c9!l#!h. 4Y4(oobarY44 H'oob#rH &he b#c9!l#!he! e!c#pe Fuote!. 4(ooYbar4 'oob#r &he b#c9!l#!h He!c#pe!H b :ote th#t the $(P 6ill ordin#rily print !tring! in re#d#ble 'or*, #dding the enclo!ing Fuot#tion *#r9! #nd #ny nece!!#ry e!c#ping b#c9!l#!he!, !o i' you 6#nt to !ee the #ctu#l content! o' # !tring, you need to u!e 'unction !uch #! FORMAT de!igned to print hu*#n-re#d#ble output. /or e.#*ple, here@! 6h#t you !ee i' you type # !tring cont#ining #n e*bedded Fuot#tion *#r9 #t the $(P :
$L-+,-./#4(ooY4bar4 4(ooY4bar4
FORMAT, on the other h#nd, 6ill !ho6 you the #ctu#l !tring content!:12
$L-+,-./#1(ormat#t#4(ooY4bar43 (oo4bar 89L
/tring #o$parisons
4ou c#n co*p#re !tring! u!ing # !et o' 'unction! th#t 'ollo6 the !#*e n#*ing con?ention #! the ch#r#cter co*p#ri!on 'unction! e.cept 6ith ,F.98J #! the pre'i. r#ther th#n $:I. B!ee &#ble 10-3C. &#ble 10-3. String Co*p#ri!on /unction! :u$eric Ana%og #ase4/ensiti,e #ase4Insensiti,e = STRING= STRING-EQUAL 0= STRING0= STRING-NOT-EQUAL 1 STRING1 STRING-LESSP 2 STRING2 STRING-GREATERP 1= STRING1= STRING-NOT-GREATERP 2= STRING2= STRING-NOT-LESSP >o6e?er, unli9e the ch#r#cter #nd nu*ber co*p#r#tor!, the !tring co*p#r#tor! c#n co*p#re only t6o !tring!. &h#t@! bec#u!e they #l!o t#9e 9ey6ord #rgu*ent! th#t #llo6 you to re!trict the co*p#ri!on to # !ub!tring o' either or both !tring!. &he #rgu*ent!--:start0, :end0, :start!, #nd :end!-!peci'y the !t#rting Binclu!i?eC #nd ending Be.clu!i?eC indice! o' !ub!tring! in the 'ir!t #nd !econd !tring #rgu*ent!. &hu!, the 'ollo6ing:
1string=#4(oobarba*4#4@'')bar(oo4#:start0#3#:end0#6#:start!#4#:end!#Q3
co*p#re! the !ub!tring Hb#rH in the t6o #rgu*ent! #nd return! true. &he :end0 #nd :end! #rgu*ent! c#n be NIL Bor the 9ey6ord #rgu*ent o*itted #ltogetherC to indic#te th#t the corre!ponding !ub!tring e.tend! to the end o' the !tring. &he co*p#r#tor! th#t return true 6hen their #rgu*ent! di''er--th#t i!, #ll o' the* e.cept STRING= #nd STRING-EQUAL--return the inde. in the 'ir!t !tring 6here the *i!*#tch 6#! detected.
1string/=#4lisp4#4lissome43#==/#3
I' the 'ir!t !tring i! # pre'i. o' the !econd, the return ?#lue 6ill be the length o' the 'ir!t !tring, th#t i!, one gre#ter th#n the l#rge!t ?#lid inde. into the !tring.
1stringO#4lisp4#4lisper43#==/#4
When co*p#ring !ub!tring!, the re!ulting ?#lue i! !till #n inde. into the !tring #! # 6hole. /or in!t#nce, the 'ollo6ing co*p#re! the !ub!tring! Hb#rH #nd Hb#AH but return! 5 bec#u!e th#t@! the inde. o' the r in the 'ir!t !tring:
1stringO#4(oobar4#4aba*4#:start0#3#:start!#03#==/#"###S#8.L.#not#!
5ther !tring 'unction! #llo6 you to con?ert the c#!e o' !tring! #nd tri* ch#r#cter! 'ro* one or both end! o' # !tring. %nd, #! I *entioned pre?iou!ly, !ince !tring! #re re#lly # 9ind o' !eFuence, #ll the !eFuence 'unction! I@ll di!cu!! in the ne.t ch#pter c#n be u!ed 6ith !tring!. /or in!t#nce, you c#n di!co?er the length o' # !tring 6ith the LENGTH 'unction #nd c#n get #nd !et indi?idu#l ch#r#cter! o' # !tring 6ith the generic !eFuence ele*ent #cce!!or 'unction, ELT, or the generic #rr#y ele*ent #cce!!or 'unction, AREF. 5r you c#n u!e the !tring-!peci'ic #cce!!or, CHAR. 7ut tho!e 'unction!, #nd other!, #re the topic o' the ne.t ch#pter, !o let@! *o?e on.
1/red
7roo9!, The M0thical Man)Month, 20th %nni?er!#ry (dition B7o!ton: %ddi!on-We!ley, 1))5C, p. 103. (*ph#!i! in origin#l.
23#ttel@! &een &#l9 35b?iou!ly,
7#rbie
the !iAe o' # nu*ber th#t c#n be repre!ented on # co*puter 6ith 'inite *e*ory i! !till li*ited in pr#cticeG 'urther*ore, the #ctu#l repre!ent#tion o' bignums u!ed in # p#rticul#r Co**on i!p i*ple*ent#tion *#y pl#ce other li*it! on the !iAe o' nu*ber th#t c#n be repre!ented. 7ut the!e li*it! #re going to be 6ell beyond H#!trono*ic#llyH l#rge nu*ber!. /or in!t#nce, the nu*ber o' #to*! in the uni?er!e i! e!ti*#ted to be le!! th#n 2Z20)G current Co**on i!p i*ple*ent#tion! c#n e#!ily h#ndle nu*ber! up to #nd beyond 2Z2021--.
-/ol9!
intere!ted in u!ing Co**on i!p 'or inten!i?e nu*eric co*put#tion !hould note th#t # n#i?e co*p#ri!on o' the per'or*#nce o' nu*eric code in Co**on i!p #nd l#ngu#ge! !uch #! C or /5$&$%: 6ill prob#bly !ho6 Co**on i!p to be *uch !lo6er. &hi! i! bec#u!e !o*ething #! !i*ple #! 12#a#b3 in Co**on i!p i! doing # lot *ore th#n the !ee*ingly eFui?#lent a#2#b in one o' tho!e l#ngu#ge!. 7ec#u!e o' i!p@! dyn#*ic typing #nd !upport 'or thing! !uch #! #rbitr#ry preci!ion r#tion#l! #nd co*ple. nu*ber!, # !ee*ingly !i*ple #ddition i! doing # lot *ore th#n #n #ddition o' t6o nu*ber! th#t #re 9no6n to be repre!ented by *#chine 6ord!. >o6e?er, you c#n u!e decl#r#tion! to gi?e Co**on i!p in'or*#tion #bout the type! o' nu*ber! you@re u!ing th#t 6ill en#ble it to gener#te code th#t doe! only #! *uch 6or9 #! the code th#t 6ould be gener#ted by # C or /5$&$%: co*piler. &uning nu*eric code 'or thi! 9ind o' per'or*#nce i! beyond the !cope o' thi! boo9, but it@! cert#inly po!!ible.
5While
the !t#nd#rd doe!n@t reFuire it, *#ny Co**on i!p i*ple*ent#tion! !upport the I((( !t#nd#rd 'or 'lo#ting-point #rith*etic, ;+++ -tandard for #inar0 ,loating)Point !rithmetic< !2-;8 ;+++ -td ='9)%>/' BIn!titute o' (lectric#l #nd (lectronic! (ngineer!, 1),5C.
0It@!
#l!o po!!ible to ch#nge the de'#ult b#!e the re#der u!e! 'or nu*ber! 6ithout # !peci'ic r#di. *#r9er by ch#nging the ?#lue o' the glob#l ?#ri#ble *READ-BASE*. >o6e?er, it@! not cle#r th#t@! the p#th to #nything other th#n co*plete in!#nity.
2Since
the purpo!e o' 'lo#ting-point nu*ber! i! to *#9e e''icient u!e o' 'lo#ting-point h#rd6#re, e#ch i!p i*ple*ent#tion i! #llo6ed to *#p the!e 'our !ubtype! onto the n#ti?e 'lo#ting-point type! #! #ppropri#te. I' the h#rd6#re !upport! 'e6er th#n 'our di!tinct repre!ent#tion!, one or *ore o' the type! *#y be eFui?#lent.
,HCo*puteriAed
!cienti'ic not#tionH i! in !c#re Fuote! bec#u!e, 6hile co**only u!ed in co*puter l#ngu#ge! !ince the d#y! o' /5$&$%:, it@! #ctu#lly Fuite di''erent 'ro* re#l !cienti'ic not#tion. In p#rticul#r, !o*ething li9e 0. e4 *e#n! 0 . , but in true !cienti'ic not#tion th#t 6ould be 6ritten #! 1.0 . 10Z-. %nd to 'urther con'u!e *#tter!, in true !cienti'ic not#tion the letter e !t#nd! 'or the b#!e o' the n#tur#l log#rith*, !o !o*ething li9e 1.0 . eZ-, 6hile !uper'ici#lly !i*il#r to 0. e4, i! # co*pletely di''erent ?#lue, #ppro.i*#tely 5-.0.
)/or
*#the*#tic#l con!i!tency, + #nd * c#n #l!o be c#lled 6ith no #rgu*ent!, in 6hich c#!e they return the #ppropri#te identity: 0 'or + #nd 1 'or *.
10$oughly
!pe#9ing, MOD i! eFui?#lent to the 6 oper#tor in Perl #nd Python, #nd REM i! eFui?#lent to the [ in C #nd D#?#. B&echnic#lly, the e.#ct beh#?ior o' [ in C 6#!n@t !peci'ied until the C)) !t#nd#rd.C
11(?en
D#?#, 6hich 6#! de!igned 'ro* the beginning to u!e 8nicode ch#r#cter! on the theory th#t 8nicode 6#! the going to be the ch#r#cter encoding o' the 'uture, h#! run into trouble !ince D#?#
ch#r#cter! #re de'ined to be # 10-bit Fu#ntity #nd the 8nicode 3.1 !t#nd#rd e.tended the r#nge o' the 8nicode ch#r#cter !et to reFuire # 21-bit repre!ent#tion. 5oop!.
12:ote,
ho6e?er, th#t not #ll liter#l !tring! c#n be printed by p#!!ing the* #! the !econd #rgu*ent to FORMAT !ince cert#in !eFuence! o' ch#r#cter! h#?e # !peci#l *e#ning to FORMAT. &o !#'ely print #n #rbitr#ry !tring--!#y, the ?#lue o' # ?#ri#ble !--6ith FORMAT you !hould 6rite B'or*#t t H\#H !C.
11. #o%%ections
i9e *o!t progr#**ing l#ngu#ge!, Co**on i!p pro?ide! !t#nd#rd d#t# type! th#t collect *ultiple ?#lue! into # !ingle ob<ect. (?ery l#ngu#ge !lice! up the collection proble* # little bit di''erently, but the b#!ic collection type! u!u#lly boil do6n to #n integer-inde.ed #rr#y type #nd # t#ble type th#t c#n be u!ed to *#p *ore or le!! #rbitr#ry 9ey! to ?#lue!. &he 'or*er #re ?#riou!ly c#lled arra0s, lists, or tuplesG the l#tter go by the n#*e! hash tables, associative arra0s, maps, #nd dictionaries. i!p i!, o' cour!e, '#*ou! 'or it! li!t d#t# !tructure, #nd *o!t i!p boo9!, 'ollo6ing the ontogenyrec#pitul#te!-phylogeny principle o' l#ngu#ge in!truction, !t#rt their di!cu!!ion o' i!p@! collection! 6ith li!t!. >o6e?er, th#t #ppro#ch o'ten le#d! re#der! to the *i!t#9en conclu!ion th#t li!t! #re i!p@! onl0 collection type. &o *#9e *#tter! 6or!e, bec#u!e i!p@! li!t! #re !uch # 'le.ible d#t# !tructure, it is po!!ible to u!e the* 'or *#ny o' the thing! #rr#y! #nd h#!h t#ble! #re u!ed 'or in other l#ngu#ge!. 7ut it@! # *i!t#9e to 'ocu! too *uch on li!t!G 6hile they@re # cruci#l d#t# !tructure 'or repre!enting i!p code #! i!p d#t#, in *#ny !itu#tion! other d#t# !tructure! #re *ore #ppropri#te. &o 9eep li!t! 'ro* !te#ling the !ho6, in thi! ch#pter I@ll 'ocu! on Co**on i!p@! other collection type!: ?ector! #nd h#!h t#ble!.1 >o6e?er, ?ector! #nd li!t! !h#re enough ch#r#cteri!tic! th#t Co**on i!p
tre#t! the* both #! !ubtype! o' # *ore gener#l #b!tr#ction, the !eFuence. &hu!, you c#n u!e *#ny o' the 'unction! I@ll di!cu!! in thi! ch#pter 6ith both ?ector! #nd li!t!.
<ectors
1ector! #re Co**on i!p@! b#!ic integer-inde.ed collection, #nd they co*e in t6o 'l#?or!. /i.ed-!iAe ?ector! #re # lot li9e #rr#y! in # l#ngu#ge !uch #! D#?#: # thin ?eneer o?er # chun9 o' contiguou! *e*ory th#t hold! the ?ector@! ele*ent!.2 $e!iA#ble ?ector!, on the other h#nd, #re *ore li9e #rr#y! in Perl or $uby, li!t! in Python, or the %rr#y i!t cl#!! in D#?#: they #b!tr#ct the #ctu#l !tor#ge, #llo6ing the ?ector to gro6 #nd !hrin9 #! ele*ent! #re #dded #nd re*o?ed. 4ou c#n *#9e 'i.ed-!iAe ?ector! cont#ining !peci'ic ?#lue! 6ith the 'unction VECTOR, 6hich t#9e! #ny nu*ber o' #rgu*ent! #nd return! # 're!hly #lloc#ted 'i.ed-!iAe ?ector cont#ining tho!e #rgu*ent!.
1vector3#####==/#N13 1vector#03###==/#N103 1vector#0#!3#==/#N10#!3
&he N1...3 !ynt#. i! the liter#l not#tion 'or ?ector! u!ed by the i!p printer #nd re#der. &hi! !ynt#. #llo6! you to !#?e #nd re!tore ?ector! by PRINTing the* out #nd READing the* b#c9 in. 4ou c#n u!e the N1...3 !ynt#. to include liter#l ?ector! in your code, but #! the e''ect! o' *odi'ying liter#l ob<ect! #ren@t de'ined, you !hould #l6#y! u!e VECTOR or the *ore gener#l 'unction MA+E-ARRAY to cre#te ?ector! you pl#n to *odi'y. MA+E-ARRAY i! *ore gener#l th#n VECTOR !ince you c#n u!e it to cre#te #rr#y! o' #ny di*en!ion#lity #! 6ell #! both 'i.ed-!iAe #nd re!iA#ble ?ector!. &he one reFuired #rgu*ent to MA+EARRAY i! # li!t cont#ining the di*en!ion! o' the #rr#y. Since # ?ector i! # one-di*en!ion#l #rr#y, thi! li!t 6ill cont#in one nu*ber, the !iAe o' the ?ector. %! # con?enience, MA+E-ARRAY 6ill #l!o #ccept # pl#in nu*ber in the pl#ce o' # one-ite* li!t. With no other #rgu*ent!, MA+E-ARRAY 6ill cre#te # ?ector 6ith uniniti#liAed ele*ent! th#t *u!t be !et be'ore they c#n be #cce!!ed.3 &o cre#te # ?ector 6ith the ele*ent! #ll !et to # p#rticul#r ?#lue, you c#n p#!! #n :initial-element #rgu*ent. &hu!, to *#9e # 'i?e-ele*ent ?ector 6ith it! ele*ent! initi#liAed to NIL, you c#n 6rite the 'ollo6ing:
1ma&e-arra?#"#:initial-element#nil3#==/#N189L#89L#89L#89L#89L3
MA+E-ARRAY i! #l!o the 'unction to u!e to *#9e # re!iA#ble ?ector. % re!iA#ble ?ector i! # !lightly *ore co*plic#ted ob<ect th#n # 'i.ed-!iAe ?ectorG in #ddition to 9eeping tr#c9 o' the *e*ory u!ed to hold the ele*ent! #nd the nu*ber o' !lot! #?#il#ble, # re!iA#ble ?ector #l!o 9eep! tr#c9 o' the nu*ber o' ele*ent! #ctu#lly !tored in the ?ector. &hi! nu*ber i! !tored in the ?ector@! fill pointer, !o c#lled bec#u!e it@! the inde. o' the ne.t po!ition to be 'illed 6hen you #dd #n ele*ent to the ?ector. &o *#9e # ?ector 6ith # 'ill pointer, you p#!! MA+E-ARRAY # :(ill-pointer #rgu*ent. /or in!t#nce, the 'ollo6ing c#ll to MA+E-ARRAY *#9e! # ?ector 6ith roo* 'or 'i?e ele*ent!G but it loo9! e*pty bec#u!e the 'ill pointer i! Aero:
1ma&e-arra?#"#:(ill-pointer# 3#==/#N13
&o #dd #n ele*ent to the end o' # re!iA#ble ?ector, you c#n u!e the 'unction VECTOR-PUSH. It #dd! the ele*ent #t the current ?#lue o' the 'ill pointer #nd then incre*ent! the 'ill pointer by one, returning the inde. 6here the ne6 ele*ent 6#! #dded. &he 'unction VECTOR-POP return! the *o!t recently pu!hed ite*, decre*enting the 'ill pointer in the proce!!.
1de(parameter#U)U#1ma&e-arra?#"#:(ill-pointer# 33
1vector-p'sh#Ca#U)U3#==/# U)U##################==/#N1I3 1vector-p'sh#Cb#U)U3#==/#0 U)U##################==/#N1I#L3 1vector-p'sh#Cc#U)U3#==/#! U)U##################==/#N1I#L#$3 1vector-pop#U)U3#####==/#$ U)U##################==/#N1I#L3 1vector-pop#U)U3#####==/#L U)U##################==/#N1I3 1vector-pop#U)U3#####==/#I U)U##################==/#N13
>o6e?er, e?en # ?ector 6ith # 'ill pointer i!n@t co*pletely re!iA#ble. &he ?ector U)U c#n hold #t *o!t 'i?e ele*ent!. &o *#9e #n #rbitr#rily re!iA#ble ?ector, you need to p#!! MA+E-ARRAY #nother 9ey6ord #rgu*ent: :adj'stable.
1ma&e-arra?#"#:(ill-pointer# #:adj'stable#t3#==/#N13
&hi! c#ll *#9e! #n adjustable ?ector 6ho!e underlying *e*ory c#n be re!iAed #! needed. &o #dd ele*ent! to #n #d<u!t#ble ?ector, you u!e VECTOR-PUSH-EXTEND, 6hich 6or9! <u!t li9e VECTORPUSH e.cept it 6ill #uto*#tic#lly e.p#nd the #rr#y i' you try to pu!h #n ele*ent onto # 'ull ?ector--one 6ho!e 'ill pointer i! eFu#l to the !iAe o' the underlying !tor#ge.-
/u2types o <ector
%ll the ?ector! you@?e de#lt 6ith !o '#r h#?e been general ?ector! th#t c#n hold #ny type o' ob<ect. It@! #l!o po!!ible to cre#te speciali6ed ?ector! th#t #re re!tricted to holding cert#in type! o' ele*ent!. 5ne re#!on to u!e !peci#liAed ?ector! i! they *#y be !tored *ore co*p#ctly #nd c#n pro?ide !lightly '#!ter #cce!! to their ele*ent! th#n gener#l ?ector!. >o6e?er, 'or the *o*ent let@! 'ocu! on # couple 9ind! o' !peci#liAed ?ector! th#t #re i*port#nt d#t# type! in their o6n right. 5ne o' the!e you@?e !een #lre#dy--!tring! #re ?ector! !peci#liAed to hold ch#r#cter!. String! #re i*port#nt enough to get their o6n re#d;print !ynt#. Bdouble Fuote!C #nd the !et o' !tring-!peci'ic 'unction! I di!cu!!ed in the pre?iou! ch#pter. 7ut bec#u!e they@re #l!o ?ector!, #ll the 'unction! I@ll di!cu!! in the ne.t 'e6 !ection! th#t t#9e ?ector #rgu*ent! c#n #l!o be u!ed 6ith !tring!. &he!e 'unction! 6ill 'ill out the !tring libr#ry 6ith 'unction! 'or thing! !uch #! !e#rching # !tring 'or # !ub!tring, 'inding occurrence! o' # ch#r#cter 6ithin # !tring, #nd *ore. iter#l !tring!, !uch #! 4(oo4, #re li9e liter#l ?ector! 6ritten 6ith the N13 !ynt#.--their !iAe i! 'i.ed, #nd they *u!t not be *odi'ied. >o6e?er, you c#n u!e MA+E-ARRAY to *#9e re!iA#ble !tring! by #dding #nother 9ey6ord #rgu*ent, :element-t?pe. &hi! #rgu*ent t#9e! # t0pe de!criptor. I 6on@t di!cu!! #ll the po!!ible type de!criptor! you c#n u!e hereG 'or no6 it@! enough to 9no6 you c#n cre#te # !tring by p#!!ing the !y*bol CHARACTER #! the :element-t?pe #rgu*ent. :ote th#t you need to Fuote the !y*bol to pre?ent it 'ro* being tre#ted #! # ?#ri#ble n#*e. /or e.#*ple, to *#9e #n initi#lly e*pty but re!iA#ble !tring, you c#n 6rite thi!:
1ma&e-arra?#"#:(ill-pointer# #:adj'stable#t#:element-t?pe#Ccharacter3##44
7it ?ector!--?ector! 6ho!e ele*ent! #re #ll Aero! or one!--#l!o get !o*e !peci#l tre#t*ent. &hey h#?e # !peci#l re#d;print !ynt#. th#t loo9! li9e NU 0000 #nd # '#irly l#rge libr#ry o' 'unction!, 6hich I 6on@t di!cu!!, 'or per'or*ing bit-t6iddling oper#tion! !uch #! H#ndingH together t6o bit #rr#y!. &he
type de!criptor to p#!! #! the :element-t?pe to cre#te # bit ?ector i! the !y*bol BIT.
<ectors As /e8uences
%! *entioned e#rlier, ?ector! #nd li!t! #re the t6o concrete !ubtype! o' the #b!tr#ct type se4uence. %ll the 'unction! I@ll di!cu!! in the ne.t 'e6 !ection! #re !eFuence 'unction!G in #ddition to being #pplic#ble to ?ector!--both gener#l #nd !peci#liAed--they c#n #l!o be u!ed 6ith li!t!. &he t6o *o!t b#!ic !eFuence 'unction! #re LENGTH, 6hich return! the length o' # !eFuence, #nd ELT, 6hich #llo6! you to #cce!! indi?idu#l ele*ent! ?i# #n integer inde.. LENGTH t#9e! # !eFuence #! it! only #rgu*ent #nd return! the nu*ber o' ele*ent! it cont#in!. /or ?ector! 6ith # 'ill pointer, thi! 6ill be the ?#lue o' the 'ill pointer. ELT, !hort 'or element, t#9e! # !eFuence #nd #n integer inde. bet6een Aero Binclu!i?eC #nd the length o' the !eFuence Be.clu!i?eC #nd return! the corre!ponding ele*ent. ELT 6ill !ign#l #n error i' the inde. i! out o' bound!. i9e LENGTH, ELT tre#t! # ?ector 6ith # 'ill pointer #! h#?ing the length !peci'ied by the 'ill pointer.
1de(parameter#U)U#1vector#0#!#333 1length#U)U3#==/#3 1elt#U)U# 3##==/#0 1elt#U)U#03##==/#! 1elt#U)U#!3##==/#3 1elt#U)U#33##==/#error
ELT i! #l!o # SETF#ble pl#ce, !o you c#n !et the ?#lue o' # p#rticul#r ele*ent li9e thi!:
1set(#1elt#U)U# 3#0 3 U)U#==/#N10 #!#33
$eFuired %rgu*ent! Ite* #nd !eFuence Ite* #nd !eFuence Ite* #nd !eFuence Ite* #nd !eFuence
1remove#NYa#4(oobarba*43###############==/#4(oobrb*4 1s'bstit'te#0 #0#N10#!#0#!#3#0#!#3#433#==/#N10 #!#0 #!#3#0 #!#3#43 1s'bstit'te#0 #0#C10#!#0#!#3#0#!#3#433#==/#10 #!#0 #!#3#0 #!#3#43 1s'bstit'te#NY)#NYb#4(oobarba*43#######==/#4(oo)ar)a*4 1(ind#0#N10#!#0#!#3#0#!#3#433##########==/#0 1(ind#0 #N10#!#0#!#3#0#!#3#433#########==/#89L 1position#0#N10#!#0#!#3#0#!#3#433######==/#
:ote ho6 REMOVE #nd SUBSTITUTE #l6#y! return # !eFuence o' the !#*e type #! their !eFuence #rgu*ent. 4ou c#n *odi'y the beh#?ior o' the!e 'i?e 'unction! in # ?#riety o' 6#y! u!ing 9ey6ord #rgu*ent!. /or in!t#nce, the!e 'unction!, by de'#ult, loo9 'or ele*ent! in the !eFuence th#t #re the !#*e ob<ect #! the ite* #rgu*ent. 4ou c#n ch#nge thi! in t6o 6#y!: /ir!t, you c#n u!e the :test 9ey6ord to p#!! # 'unction th#t #ccept! t6o #rgu*ent! #nd return! # boole#n. I' pro?ided, it 6ill be u!ed to co*p#re item to e#ch ele*ent in!te#d o' the de'#ult ob<ect eFu#lity te!t, EQL.5 Second, 6ith the :&e? 9ey6ord you c#n p#!! # one-#rgu*ent 'unction to be c#lled on e#ch ele*ent o' the !eFuence to e.tr#ct # $e0 ?#lue, 6hich 6ill then be co*p#red to the ite* in the pl#ce o' the ele*ent it!el'. :ote, ho6e?er, th#t 'unction! !uch #! FIND th#t return ele*ent! o' the !eFuence continue to return the #ctu#l ele*ent, not <u!t the e.tr#cted 9ey.
1co'nt#4(oo4#N14(oo4#4bar4#4ba*43#:test#NCstring=3####==/#0 1(ind#Cc#N11a#0 3#1b#! 3#1c#3 3#1d#4 33#:&e?#NC(irst3#==/#1$#3 3
&o li*it the e''ect! o' the!e 'unction! to # p#rticul#r !ub!eFuence o' the !eFuence #rgu*ent, you c#n pro?ide bounding indice! 6ith :start #nd :end #rgu*ent!. P#!!ing NIL 'or :end or o*itting it i! the !#*e #! !peci'ying the length o' the !eFuence.0 I' # non-NIL :(rom-end #rgu*ent i! pro?ided, then the ele*ent! o' the !eFuence 6ill be e.#*ined in re?er!e order. 7y it!el' :(rom-end c#n #''ect the re!ult! o' only FIND #nd POSITION. /or in!t#nce:
1(ind#Ca#N11a#0 3#1b#! 3#1a#3 3#1b#4 33#:&e?#NC(irst3#############==/#1I#0 3 1(ind#Ca#N11a#0 3#1b#! 3#1a#3 3#1b#4 33#:&e?#NC(irst#:(rom-end#t3#==/#1I#3 3
>o6e?er, the :(rom-end #rgu*ent c#n #''ect REMOVE #nd SUBSTITUTE in con<unction 6ith #nother 9ey6ord p#r#*eter, :co'nt, th#t@! u!ed to !peci'y ho6 *#ny ele*ent! to re*o?e or !ub!titute. I' you !peci'y # :co'nt lo6er th#n the nu*ber o' *#tching ele*ent!, then it ob?iou!ly *#tter! 6hich end you !t#rt 'ro*:
1remove#NYa#4(oobarba*4#:co'nt#03#############==/#4(oobrba*4 1remove#NYa#4(oobarba*4#:co'nt#0#:(rom-end#t3#==/#4(oobarb*4
%nd 6hile :(rom-end c#n@t ch#nge the re!ult! o' the COUNT 'unction, it doe! #''ect the order the ele*ent! #re p#!!ed to #ny :test #nd :&e? 'unction!, 6hich could po!!ibly h#?e !ide e''ect!. /or e.#*ple:
$L-+,-./#1de(parameter#UvU#N11a#0 3#1b#! 3#1a#3 3#1b#4 333 UKU $L-+,-./#1de('n#verbose-(irst#1)3#1(ormat#t#4Loo&ing#at#7s764#)3#1(irst#)33 K-.L;,--E9.,F $L-+,-./#1co'nt#Ca#UvU#:&e?#NCverbose-(irst3 Loo&ing#at#1I#0 3 Loo&ing#at#1L#! 3 Loo&ing#at#1I#3 3
&#ble 11-2 !u**#riAe! the!e #rgu*ent!. &#ble 11-2. St#nd#rd SeFuence /unction Ley6ord %rgu*ent! %rgu*ent 3e#ning &6o-#rgu*ent 'unction u!ed to co*p#re ite* Bor ?#lue e.tr#cted by :&e? :test 'unctionC to ele*ent. 5ne-#rgu*ent 'unction to e.tr#ct 9ey ?#lue 'ro* #ctu#l !eFuence ele*ent. :&e? NIL *e#n! u!e ele*ent #! i!. :start St#rting inde. Binclu!i?eC o' !ub!eFuence. :end (nding inde. Be.clu!i?eC o' !ub!eFuence. NIL indic#te! end o' !eFuence. :(rom-end I' true, the !eFuence 6ill be tr#?er!ed in re?er!e order, 'ro* end to !t#rt. :u*ber indic#ting the nu*ber o' ele*ent! to re*o?e or !ub!titute or NIL to :co'nt indic#te #ll BREMOVE #nd SUBSTITUTE onlyC. +e'#ult EQL NIL 0 NIL NIL NIL
%ccording to the l#ngu#ge !t#nd#rd, the -IF-NOT ?#ri#nt! #re deprec#ted. >o6e?er, th#t deprec#tion i! gener#lly con!idered to h#?e it!el' been ill-#d?i!ed. I' the !t#nd#rd i! e?er re?i!ed, it@! *ore li9ely the deprec#tion 6ill be re*o?ed th#n the -IF-NOT 'unction!. /or one thing, the REMOVE-IF-NOT ?#ri#nt i! prob#bly u!ed *ore o'ten th#n REMOVE-IF. +e!pite it! neg#ti?e-!ounding n#*e, REMOVEIF-NOT i! #ctu#lly the po!iti?e ?#ri#nt--it return! the ele*ent! th#t do !#ti!'y the predic#te. 2 &he -9E #nd -9E-8;F ?#ri#nt! #ccept #ll the !#*e 9ey6ord #rgu*ent! #! their ?#nill# counterp#rt! e.cept 'or :test, 6hich i!n@t needed !ince the *#in #rgu*ent i! #lre#dy # 'unction., With # :&e? #rgu*ent, the ?#lue e.tr#cted by the :&e? 'unction i! p#!!ed to the 'unction in!te#d o' the #ctu#l ele*ent.
&he REMOVE '#*ily o' 'unction! #l!o !upport # 'ourth ?#ri#nt, REMOVE-DUPLICATES, th#t h#! only one reFuired #rgu*ent, # !eFuence, 'ro* 6hich it re*o?e! #ll but one in!t#nce o' e#ch duplic#ted ele*ent. It t#9e! the !#*e 9ey6ord #rgu*ent! #! REMOVE, e.cept 'or :co'nt, !ince it #l6#y! re*o?e! #ll duplic#te!.
1remove-d'plicates#N10#!#0#!#3#0#!#3#433#==/#N10#!#3#43
&he di''erence i! th#t STABLE-SORT i! gu#r#nteed to not reorder #ny ele*ent! con!idered eFui?#lent by the predic#te 6hile SORT gu#r#ntee! only th#t the re!ult i! !orted #nd *#y reorder eFui?#lent ele*ent!. 7oth the!e 'unction! #re e.#*ple! o' 6h#t #re c#lled destructive 'unction!. +e!tructi?e 'unction! #re #llo6ed--typic#lly 'or re#!on! o' e''iciency--to *odi'y their #rgu*ent! in *ore or le!! #rbitr#ry 6#y!. &hi! h#! t6o i*plic#tion!: one, you !hould #l6#y! do !o*ething 6ith the return ?#lue o' the!e 'unction! B!uch #! #!!ign it to # ?#ri#ble or p#!! it to #nother 'unctionC, #nd, t6o, unle!! you@re done 6ith the ob<ect you@re p#!!ing to the de!tructi?e 'unction, you !hould p#!! # copy in!te#d. I@ll !#y *ore #bout de!tructi?e 'unction! in the ne.t ch#pter.
&ypic#lly you 6on@t c#re #bout the un!orted ?er!ion o' # !eFuence #'ter you@?e !orted it, !o it *#9e! !en!e to #llo6 SORT #nd STABLE-SORT to de!troy the !eFuence in the cour!e o' !orting it. 7ut it doe! *e#n you need to re*e*ber to 6rite the 'ollo6ing:10
1set(#m?-se@'ence#1sort#m?-se@'ence#NCstringO33
7oth the!e 'unction! #l!o t#9e # 9ey6ord #rgu*ent, :&e?, 6hich, li9e the :&e? #rgu*ent in other !eFuence 'unction!, !hould be # 'unction #nd 6ill be u!ed to e.tr#ct the ?#lue! to be p#!!ed to the !orting predic#te in the pl#ce o' the #ctu#l ele*ent!. &he e.tr#cted 9ey! #re u!ed only to deter*ine the ordering o' ele*ent!G the !eFuence returned 6ill cont#in the #ctu#l ele*ent! o' the #rgu*ent !eFuence. &he MERGE 'unction t#9e! t6o !eFuence! #nd # predic#te #nd return! # !eFuence produced by *erging the t6o !eFuence!, #ccording to the predic#te. It@! rel#ted to the t6o !orting 'unction! in th#t i' e#ch !eFuence i! #lre#dy !orted by the !#*e predic#te, then the !eFuence returned by MERGE 6ill #l!o be !orted. i9e the !orting 'unction!, MERGE t#9e! # :&e? #rgu*ent. i9e CONCATENATE, #nd 'or the !#*e re#!on, the 'ir!t #rgu*ent to MERGE *u!t be # type de!criptor !peci'ying the type o' !eFuence to produce.
1merge#Cvector#N10#3#"3#N1!#4#63#NCO3#==/#N10#!#3#4#"#63 1merge#Clist#N10#3#"3#N1!#4#63#NCO3###==/#10#!#3#4#"#63
/u2se8uence +anipu%ations
%nother !et o' 'unction! #llo6! you to *#nipul#te !ub!eFuence! o' e.i!ting !eFuence!. &he *o!t b#!ic o' the!e i! SUBSEQ, 6hich e.tr#ct! # !ub!eFuence !t#rting #t # p#rticul#r inde. #nd continuing to # p#rticul#r ending inde. or the end o' the !eFuence. /or in!t#nce:
1s'bse@#4(oobarba*4#33###==/#4barba*4 1s'bse@#4(oobarba*4#3#63#==/#4bar4
SUBSEQ i! #l!o SETF#ble, but it 6on@t e.tend or !hrin9 # !eFuenceG i' the ne6 ?#lue #nd the !ub!eFuence to be repl#ced #re di''erent length!, the !horter o' the t6o deter*ine! ho6 *#ny ch#r#cter! #re #ctu#lly ch#nged.
1de(parameter#U)U#1cop?-se@#4(oobarba*433 1set(#1s'bse@#U)U#3#63#4)))43##S#s'bse@'ence#and#new#val'e#are#same#length U)U#==/#4(oo)))ba*4 1set(#1s'bse@#U)U#3#63#4abcd43#S#new#val'e#too#long5#e)tra#character#ignored. U)U#==/#4(ooabcba*4 1set(#1s'bse@#U)U#3#63#4))43###S#new#val'e#too#short5#onl?#two#characters#changed U)U#==/#4(oo))cba*4
4ou c#n u!e the FILL 'unction to !et *ultiple ele*ent! o' # !eFuence to # !ingle ?#lue. &he reFuired #rgu*ent! #re # !eFuence #nd the ?#lue 6ith 6hich to 'ill it. 7y de'#ult e?ery ele*ent o' the !eFuence i! !et to the ?#lueG :start #nd :end 9ey6ord #rgu*ent! c#n li*it the e''ect! to # gi?en !ub!eFuence. I' you need to 'ind # !ub!eFuence 6ithin # !eFuence, the SEARCH 'unction 6or9! li9e POSITION
5n the other h#nd, to 'ind 6here t6o !eFuence! 6ith # co**on pre'i. 'ir!t di?erge, you c#n u!e the MISMATCH 'unction. It t#9e! t6o !eFuence! #nd return! the inde. o' the 'ir!t p#ir o' *i!*#tched ele*ent!.
1mismatch#4(oobarba*4#4(oom43#==/#3
It return! NIL i' the !tring! *#tch. MISMATCH #l!o t#9e! *#ny o' the !t#nd#rd 9ey6ord #rgu*ent!: # :&e? #rgu*ent 'or !peci'ying # 'unction to u!e to e.tr#ct the ?#lue! to be co*p#redG # :test #rgu*ent to !peci'y the co*p#ri!on 'unctionG #nd :start0, :end0, :start!, #nd :end! #rgu*ent! to !peci'y !ub!eFuence! 6ithin the t6o !eFuence!. %nd # :(rom-end #rgu*ent o' T !peci'ie! the !eFuence! !hould be !e#rched in re?er!e order, c#u!ing MISMATCH to return the inde., in the 'ir!t !eFuence, 6here 6h#te?er co**on !u''i. the t6o !eFuence! !h#re begin!.
1mismatch#4(oobar4#4bar4#:(rom-end#t3#==/#3
/e8uence "redicates
/our other h#ndy 'unction! #re EVERY, SOME, NOTANY, #nd NOTEVERY, 6hich iter#te o?er !eFuence! te!ting # boole#n predic#te. &he 'ir!t #rgu*ent to #ll the!e 'unction! i! the predic#te, #nd the re*#ining #rgu*ent! #re !eFuence!. &he predic#te !hould t#9e #! *#ny #rgu*ent! #! the nu*ber o' !eFuence! p#!!ed. &he ele*ent! o' the !eFuence! #re p#!!ed to the predic#te--one ele*ent 'ro* e#ch !eFuence--until one o' the !eFuence! run! out o' ele*ent! or the o?er#ll ter*in#tion te!t i! *et: EVERY ter*in#te!, returning '#l!e, #! !oon #! the predic#te '#il!. I' the predic#te i! #l6#y! !#ti!'ied, it return! true. SOME return! the 'ir!t non-NIL ?#lue returned by the predic#te or return! '#l!e i' the predic#te i! ne?er !#ti!'ied. NOTANY return! '#l!e #! !oon #! the predic#te i! !#ti!'ied or true i' it ne?er i!. %nd NOTEVERY return! true #! !oon #! the predic#te '#il! or '#l!e i' the predic#te i! #l6#y! !#ti!'ied. >ere #re !o*e e.#*ple! o' te!ting <u!t one !eFuence:
1ever?#NCevenp#N10#!#3#4#"33####==/#89L 1some#NCevenp#N10#!#3#4#"33#####==/#F 1notan?#NCevenp#N10#!#3#4#"33###==/#89L 1notever?#NCevenp#N10#!#3#4#"33#==/#F
MAP-INTO i! li9e MAP e.cept in!te#d o' producing # ne6 !eFuence o' # gi?en type, it pl#ce! the re!ult! into # !eFuence p#!!ed #! the 'ir!t #rgu*ent. &hi! !eFuence c#n be the !#*e #! one o' the !eFuence! pro?iding ?#lue! 'or the 'unction. /or in!t#nce, to !u* !e?er#l ?ector!--a, b, #nd c--into one, you could 6rite thi!:
1map-into#a#NC2#a#b#c3
I' the !eFuence! #re di''erent length!, MAP-INTO #''ect! only #! *#ny ele*ent! #! #re pre!ent in the !horte!t !eFuence, including the !eFuence being *#pped into. >o6e?er, i' the !eFuence being *#pped into i! # ?ector 6ith # 'ill pointer, the nu*ber o' ele*ent! #''ected i!n@t li*ited by the 'ill pointer but r#ther by the #ctu#l !iAe o' the ?ector. %'ter # c#ll to MAP-INTO, the 'ill pointer 6ill be !et to the nu*ber o' ele*ent! *#pped. MAP-INTO 6on@t, ho6e?er, e.tend #n #d<u!t#ble ?ector. &he l#!t !eFuence 'unction i! REDUCE, 6hich doe! #nother 9ind o' *#pping: it *#p! o?er # !ingle !eFuence, #pplying # t6o-#rgu*ent 'unction 'ir!t to the 'ir!t t6o ele*ent! o' the !eFuence #nd then to the ?#lue returned by the 'unction #nd !ub!eFuent ele*ent! o' the !eFuence. &hu!, the 'ollo6ing e.pre!!ion !u*! the nu*ber! 'ro* one to ten:
1red'ce#NC2#N10#!#3#4#"#6#Q#R#9#0 33#==/#""
REDUCE i! # !urpri!ingly u!e'ul 'unction--6hene?er you need to di!till # !eFuence do6n to # !ingle ?#lue, ch#nce! #re you c#n 6rite it 6ith REDUCE, #nd it 6ill o'ten be Fuite # conci!e 6#y to e.pre!! 6h#t you 6#nt. /or in!t#nce, to 'ind the *#.i*u* ?#lue in # !eFuence o' nu*ber!, you c#n 6rite 1red'ce#NCma)#n'mbers3. REDUCE #l!o t#9e! # 'ull co*ple*ent o' 9ey6ord #rgu*ent! B:&e?, :(rom-end, :start, #nd :endC #nd one uniFue to REDUCE B:initial-val'eC. &he l#tter !peci'ie! # ?#lue th#t@! logic#lly pl#ced be'ore the 'ir!t ele*ent o' the !eFuence Bor #'ter the l#!t i' you #l!o !peci'y # true :(rom-end #rgu*entC.
.ash Ta2%es
&he other gener#l-purpo!e collection pro?ided by Co**on i!p i! the h#!h t#ble. Where ?ector! pro?ide #n integer-inde.ed d#t# !tructure, h#!h t#ble! #llo6 you to u!e #rbitr#ry ob<ect! #! the inde.e!, or 9ey!. When you #dd # ?#lue to # h#!h t#ble, you !tore it under # p#rticul#r 9ey. #ter you c#n u!e the !#*e 9ey to retrie?e the ?#lue. 5r you c#n #!!oci#te # ne6 ?#lue 6ith the !#*e 9ey--e#ch 9ey *#p! to # !ingle ?#lue. With no #rgu*ent! MA+E-HASH-TABLE *#9e! # h#!h t#ble th#t con!ider! t6o 9ey! eFui?#lent i' they@re the !#*e ob<ect #ccording to EQL. &hi! i! # good de'#ult unle!! you 6#nt to u!e !tring! #! 9ey!, !ince t6o !tring! 6ith the !#*e content! #ren@t nece!!#rily EQL. In th#t c#!e you@ll 6#nt # !o-c#lled EQUAL h#!h t#ble, 6hich you c#n get by p#!!ing the !y*bol EQUAL #! the :test 9ey6ord #rgu*ent to MA+E-HASH-TABLE. &6o other po!!ible ?#lue! 'or the :test #rgu*ent #re the !y*bol! EQ #nd EQUALP. &he!e #re, o' cour!e, the n#*e! o' the !t#nd#rd ob<ect co*p#ri!on 'unction!, 6hich I di!cu!!ed in Ch#pter -. >o6e?er, unli9e the :test #rgu*ent p#!!ed to !eFuence 'unction!, MA+EHASH-TABLE@! :test c#n@t be u!ed to !peci'y #n #rbitr#ry 'unction--only the ?#lue! EQ, EQL, EQUAL, #nd EQUALP. &hi! i! bec#u!e h#!h t#ble! #ctu#lly need t6o 'unction!, #n eFui?#lence 'unction #nd # hash 'unction th#t co*pute! # nu*eric#l h#!h code 'ro* the 9ey in # 6#y co*p#tible 6ith ho6 the eFui?#lence 'unction 6ill ulti*#tely co*p#re t6o 9ey!. >o6e?er, #lthough the l#ngu#ge !t#nd#rd pro?ide! only 'or h#!h t#ble! th#t u!e the !t#nd#rd eFui?#lence 'unction!, *o!t i*ple*ent#tion! pro?ide !o*e *ech#ni!* 'or de'ining cu!to* h#!h t#ble!.
&he GETHASH 'unction pro?ide! #cce!! to the ele*ent! o' # h#!h t#ble. It t#9e! t6o #rgu*ent!--# 9ey #nd the h#!h t#ble--#nd return! the ?#lue, i' #ny, !tored in the h#!h t#ble under th#t 9ey or NIL.11 /or e.#*ple:
1de(parameter#UhU#1ma&e-hash-table33 1gethash#C(oo#UhU3#==/#89L 1set(#1gethash#C(oo#UhU3#C@'')3 1gethash#C(oo#UhU3#==/#Z++[
Since GETHASH return! NIL i' the 9ey i!n@t pre!ent in the t#ble, there@! no 6#y to tell 'ro* the return ?#lue the di''erence bet6een # 9ey not being in # h#!h t#ble #t #ll #nd being in the t#ble 6ith the ?#lue NIL. GETHASH !ol?e! thi! proble* 6ith # 'e#ture I h#?en@t di!cu!!ed yet--*ultiple return ?#lue!. GETHASH #ctu#lly return! t6o ?#lue!G the pri*#ry ?#lue i! the ?#lue !tored under the gi?en 9ey or NIL. &he !econd#ry ?#lue i! # boole#n indic#ting 6hether the 9ey i! pre!ent in the h#!h t#ble. 7ec#u!e o' the 6#y *ultiple ?#lue! 6or9, the e.tr# return ?#lue i! !ilently di!c#rded unle!! the c#ller e.plicitly h#ndle! it 6ith # 'or* th#t c#n H!eeH *ultiple ?#lue!. I@ll di!cu!! *ultiple return ?#lue! in gre#ter det#il in Ch#pter 20, but 'or no6 I@ll gi?e you # !ne#9 pre?ie6 o' ho6 to u!e the MULTIPLE-VALUE-BIND *#cro to t#9e #d?#nt#ge o' GETHASH@! e.tr# return ?#lue. MULTIPLE-VALUE-BIND cre#te! ?#ri#ble binding! li9e LET doe!, 'illing the* 6ith the *ultiple ?#lue! returned by # 'or*. &he 'ollo6ing 'unction !ho6! ho6 you *ight u!e MULTIPLE-VALUE-BINDG the ?#ri#ble! it bind! #re val'e #nd present:
1de('n#show-val'e#1&e?#hash-table3 ##1m'ltiple-val'e-bind#1val'e#present3#1gethash#&e?#hash-table3 ####1i(#present ######1(ormat#nil#4Kal'e#7a#act'all?#present.4#val'e3 ######1(ormat#nil#4Kal'e#7a#beca'se#&e?#not#(o'nd.4#val'e3333 1set(#1gethash#Cbar#UhU3#nil3#S#provide#an#e)plicit#val'e#o(#NIL 1show-val'e#C(oo#UhU3#==/#4Kal'e#Z++[#act'all?#present.4 1show-val'e#Cbar#UhU3#==/#4Kal'e#89L#act'all?#present.4 1show-val'e#Cba*#UhU3#==/#4Kal'e#89L#beca'se#&e?#not#(o'nd.4
Since !etting the ?#lue under # 9ey to NIL le#?e! the 9ey in the t#ble, you@ll need #nother 'unction to co*pletely re*o?e # 9ey;?#lue p#ir. REMHASH t#9e! the !#*e #rgu*ent! #! GETHASH #nd re*o?e! the !peci'ied entry. 4ou c#n #l!o co*pletely cle#r # h#!h t#ble o' #ll it! 9ey;?#lue p#ir! 6ith CLRHASH.
&he con!eFuence! o' #dding or re*o?ing ele*ent! 'ro* # h#!h t#ble 6hile iter#ting o?er it #ren@t
!peci'ied B#nd #re li9ely to be b#dC 6ith t6o e.ception!: you c#n u!e SETF 6ith GETHASH to ch#nge the ?#lue o' the current entry, #nd you c#n u!e REMHASH to re*o?e the current entry. /or in!t#nce, to re*o?e #ll the entrie! 6ho!e ?#lue i! le!! th#n ten, you could 6rite thi!:
1maphash#NC1lambda#1&#v3#1when#1O#v#0 3#1remhash#&#UhU333#UhU3
&he other 6#y to iter#te o?er # h#!h t#ble i! 6ith the e.tended LOOP *#cro, 6hich I@ll di!cu!! in Ch#pter 22.12 &he LOOP eFui?#lent o' the 'ir!t MAPHASH e.pre!!ion 6ould loo9 li9e thi!:
1loop#(or#&#being#the#hash-&e?s#in#UhU#'sing#1hash-val'e#v3 ##do#1(ormat#t#47a#=/#7a764#&#v33
I could !#y # lot *ore #bout the nonli!t collection! !upported by Co**on i!p. /or in!t#nce, I h#?en@t di!cu!!ed *ultidi*en!ion#l #rr#y! #t #ll or the libr#ry o' 'unction! 'or *#nipul#ting bit #rr#y!. >o6e?er, 6h#t I@?e co?ered in thi! ch#pter !hould !u''ice 'or *o!t o' your gener#l-purpo!e progr#**ing need!. :o6 it@! 'in#lly ti*e to loo9 #t i!p@! epony*ou! d#t# !tructure: li!t!.
15nce
you@re '#*ili#r 6ith #ll the d#t# type! Co**on i!p o''er!, you@ll #l!o !ee th#t li!t! c#n be u!e'ul 'or prototyping d#t# !tructure! th#t 6ill l#ter be repl#ced 6ith !o*ething *ore e''icient once it beco*e! cle#r ho6 e.#ctly the d#t# i! to be u!ed.
21ector!
#re c#lled vectors, not arra0s #! their #n#log! in other l#ngu#ge! #re, bec#u!e Co**on i!p !upport! true *ultidi*en!ion#l #rr#y!. It@! eFu#lly correct, though *ore cu*ber!o*e, to re'er to the* #! one)dimensional arra0s.
3%rr#y
ele*ent! H*u!tH be !et be'ore they@re #cce!!ed in the !en!e th#t the beh#?ior i! unde'inedG i!p 6on@t nece!!#rily !top you.
-While
'reFuently u!ed together, the :(ill-pointer #nd :adj'stable #rgu*ent! #re independent--you c#n *#9e #n #d<u!t#ble #rr#y 6ithout # 'ill pointer. >o6e?er, you c#n u!e VECTORPUSH #nd VECTOR-POP only 6ith ?ector! th#t h#?e # 'ill pointer #nd VECTOR-PUSH-EXTEND only 6ith ?ector! th#t h#?e # 'ill pointer #nd #re #d<u!t#ble. 4ou c#n #l!o u!e the 'unction AD4UST-ARRAY to *odi'y #d<u!t#ble #rr#y! in # ?#riety o' 6#y! beyond <u!t e.tending the length o' # ?ector.
5%nother
p#r#*eter, :test-not p#r#*eter, !peci'ie! # t6o-#rgu*ent predic#te to be u!ed li9e # :test #rgu*ent e.cept 6ith the boole#n re!ult logic#lly re?er!ed. &hi! p#r#*eter i! deprec#ted, ho6e?er, in pre'erence 'or u!ing the COMPLEMENT 'unction. COMPLEMENT t#9e! # 'unction #rgu*ent #nd return! # 'unction th#t t#9e! the !#*e nu*ber o' #rgu*ent! #! the origin#l #nd return! the logic#l co*ple*ent o' the origin#l 'unction. &hu!, you c#n, #nd !hould, 6rite thi!:
1co'nt#)#se@'ence#:test#1complement#NCsome-test33
:ote, ho6e?er, th#t the e''ect o' :start #nd :end on REMOVE #nd SUBSTITUTE i! only to li*it the ele*ent! they con!ider 'or re*o?#l or !ub!titutionG ele*ent! be'ore :start #nd #'ter :end 6ill be p#!!ed through untouched.
2&hi! ,&he
!#*e 'unction#lity goe! by the n#*e grep in Perl #nd (ilter in Python. di''erence bet6een the predic#te! p#!!ed #! :test #rgu*ent! #nd #! the 'unction #rgu*ent! to
the -9E #nd -9E-8;F 'unction! i! th#t the :test predic#te! #re t6o-#rgu*ent predic#te! u!ed to co*p#re the ele*ent! o' the !eFuence to the !peci'ic ite* 6hile the -9E #nd -9E-8;F predic#te! #re one-#rgu*ent 'unction! th#t !i*ply te!t the indi?idu#l ele*ent! o' the !eFuence. I' the ?#nill# ?#ri#nt! didn@t e.i!t, you could i*ple*ent the* in ter*! o' the -I/ ?er!ion! by e*bedding # !peci'ic ite* in the te!t 'unction.
1co'nt#char#string3#=== ##1co'nt-i(#NC1lambda#1c3#1e@l#char#c33#string3 1co'nt#char#string#:test#NC$:I.--Z+IL3#=== ##1co'nt-i(#NC1lambda#1c3#1char-e@'al#char#c33#string3
)
I' you tell CONCATENATE to return # !peci#liAed ?ector, !uch #! # !tring, #ll the ele*ent! o' the #rgu*ent !eFuence! *u!t be in!t#nce! o' the ?ector@! ele*ent type.
10When
the !eFuence p#!!ed to the !orting 'unction! i! # ?ector, the Hde!tructionH i! #ctu#lly gu#r#nteed to ent#il per*uting the ele*ent! in pl#ce, !o you could get #6#y 6ithout !#?ing the returned ?#lue. >o6e?er, it@! good !tyle to #l6#y! do !o*ething 6ith the return ?#lue !ince the !orting 'unction! c#n *odi'y li!t! in *uch *ore #rbitr#ry 6#y!.
117y
#n #ccident o' hi!tory, the order o' #rgu*ent! to GETHASH i! the oppo!ite o' ELT--ELT t#9e! the collection 'ir!t #nd then the inde. 6hile GETHASH t#9e! the 9ey 'ir!t #nd then the collection.
12LOOP@!
h#!h t#ble iter#tion i! typic#lly i*ple*ented on top o' # *ore pri*iti?e 'or*, WITH-HASHTABLE-ITERATOR, th#t you don@t need to 6orry #boutG it 6#! #dded to the l#ngu#ge !peci'ic#lly to !upport i*ple*enting thing! !uch #! LOOP #nd i! o' little u!e unle!! you need to 6rite co*pletely ne6 control con!truct! 'or iter#ting o?er h#!h t#ble!.
-There Is :o List/poon Boy: +o not try #nd bend the li!t. &h#t@! i*po!!ible. In!te#d . . . only try to re#liAe the truth. :eo: Wh#t truth" /poon Boy: &here i! no li!t. :eo: &here i! no li!t" /poon Boy: &hen you@ll !ee th#t it i! not the li!t th#t bend!G it i! only your!el'.1 &he 9ey to under!t#nding li!t! i! to under!t#nd th#t they@re l#rgely #n illu!ion built on top o' ob<ect! th#t #re in!t#nce! o' # *ore pri*iti?e d#t# type. &ho!e !i*pler ob<ect! #re p#ir! o' ?#lue! c#lled cons cells, #'ter the 'unction CONS u!ed to cre#te the*. CONS t#9e! t6o #rgu*ent! #nd return! # ne6 con! cell cont#ining the t6o ?#lue!.2 &he!e ?#lue! c#n be re'erence! to #ny 9ind o' ob<ect. 8nle!! the !econd ?#lue i! NIL or #nother con! cell, # con! i! printed #! the t6o ?#lue! in p#renthe!e! !ep#r#ted by # dot, # !o-c#lled dotted p#ir.
1cons#0#!3#==/#10#.#!3
&he t6o ?#lue! in # con! cell #re c#lled the CAR #nd the CDR #'ter the n#*e! o' the 'unction! u!ed to #cce!! the*. %t the d#6n o' ti*e, the!e n#*e! 6ere *ne*onic, #t le#!t to the 'ol9! i*ple*enting the 'ir!t i!p on #n I73 20-. 7ut e?en then they 6ere <u!t li'ted 'ro* the #!!e*bly *ne*onic! u!ed to i*ple*ent the oper#tion!. >o6e?er, it@! not #ll b#d th#t the!e n#*e! #re !o*e6h#t *e#ningle!!--6hen con!idering indi?idu#l con! cell!, it@! be!t to thin9 o' the* !i*ply #! #n #rbitr#ry p#ir o' ?#lue! 6ithout #ny p#rticul#r !e*#ntic!. &hu!:
1car#1cons#0#!33#==/#0 1cdr#1cons#0#!33#==/#!
7oth CAR #nd CDR #re #l!o SETF#ble pl#ce!--gi?en #n e.i!ting con! cell, it@! po!!ible to #!!ign # ne6 ?#lue to either o' it! ?#lue!.3
1de(parameter#UconsU#1cons#0#!33 UconsU#################==/#10#.#!3 1set(#1car#UconsU3#0 3#==/#0 UconsU#################==/#10 #.#!3 1set(#1cdr#UconsU3#! 3#==/#! UconsU#################==/#10 #.#! 3
7ec#u!e the ?#lue! in # con! cell c#n be re'erence! to #ny 9ind o' ob<ect, you c#n build l#rger !tructure! out o' con! cell! by lin9ing the* together. i!t! #re built by lin9ing together con! cell! in # ch#in. &he ele*ent! o' the li!t #re held in the CAR! o' the con! cell! 6hile the lin9! to !ub!eFuent con! cell! #re held in the CDR!. &he l#!t cell in the ch#in h#! # CDR o' NIL, 6hich--#! I *entioned in Ch#pter --repre!ent! the e*pty li!t #! 6ell #! the boole#n ?#lue '#l!e. &hi! #rr#nge*ent i! by no *e#n! uniFue to i!pG it@! c#lled # singl0 lin$ed list. >o6e?er, 'e6 l#ngu#ge! out!ide the i!p '#*ily pro?ide !uch e.ten!i?e !upport 'or thi! hu*ble d#t# type. So 6hen I !#y # p#rticul#r ?#lue i! # li!t, 6h#t I re#lly *e#n i! it@! either NIL or # re'erence to # con!
cell. &he CAR o' the con! cell i! the 'ir!t ite* o' the li!t, #nd the CDR i! # re'erence to #nother li!t, th#t i!, #nother con! cell or NIL, cont#ining the re*#ining ele*ent!. &he i!p printer under!t#nd! thi! con?ention #nd print! !uch ch#in! o' con! cell! #! p#renthe!iAed li!t! r#ther th#n #! dotted p#ir!.
1cons#0#nil3###################==/#103 1cons#0#1cons#!#nil33##########==/#10#!3 1cons#0#1cons#!#1cons#3#nil333#==/#10#!#33
When t#l9ing #bout !tructure! built out o' con! cell!, # 'e6 di#gr#*! c#n be # big help. 7o.-#nd-#rro6 di#gr#*! repre!ent con! cell! #! # p#ir o' bo.e! li9e thi!:
&he bo. on the le't repre!ent! the CAR, #nd the bo. on the right i! the CDR. &he ?#lue! !tored in # p#rticul#r con! cell #re either dr#6n in the #ppropri#te bo. or repre!ented by #n #rro6 'ro* the bo. to # repre!ent#tion o' the re'erenced ?#lue.- /or in!t#nce, the li!t 10#!#33, 6hich con!i!t! o' three con! cell! lin9ed together by their CDR!, 6ould be di#gr#**ed li9e thi!:
>o6e?er, *o!t o' the ti*e you 6or9 6ith li!t! you 6on@t h#?e to de#l 6ith indi?idu#l con! cell!--the 'unction! th#t cre#te #nd *#nipul#te li!t! t#9e c#re o' th#t 'or you. /or e.#*ple, the LIST 'unction build! # con! cell! under the co?er! 'or you #nd lin9! the* togetherG the 'ollo6ing LIST e.pre!!ion! #re eFui?#lent to the pre?iou! CONS e.pre!!ion!:
1list#03#####==/#103 1list#0#!3###==/#10#!3 1list#0#!#33#==/#10#!#33
Si*il#rly, 6hen you@re thin9ing in ter*! o' li!t!, you don@t h#?e to u!e the *e#ningle!! n#*e! CAR #nd CDRG FIRST #nd REST #re !ynony*! 'or CAR #nd CDR th#t you !hould u!e 6hen you@re de#ling 6ith con! cell! #! li!t!.
1de(parameter#UlistU#1list#0#!#3#433 1(irst#UlistU3########==/#0 1rest#UlistU3#########==/#1!#3#43 1(irst#1rest#UlistU33#==/#!
7ec#u!e con! cell! c#n hold #ny 9ind o' ?#lue!, !o c#n li!t!. %nd # !ingle li!t c#n hold ob<ect! o' di''erent type!.
1list#4(oo4#1list#0#!3#0 3#==/#14(oo4#10#!3#0 3
7ec#u!e li!t! c#n h#?e other li!t! #! ele*ent!, you c#n #l!o u!e the* to repre!ent tree! o' #rbitr#ry depth #nd co*ple.ity. %! !uch, they *#9e e.cellent repre!ent#tion! 'or #ny heterogeneou!, hier#rchic#l d#t#. i!p-b#!ed N3 proce!!or!, 'or in!t#nce, u!u#lly repre!ent N3 docu*ent! intern#lly #! li!t!. %nother ob?iou! e.#*ple o' tree-!tructured d#t# i! i!p code it!el'. In Ch#pter! 30 #nd 31 you@ll 6rite
#n >&3 gener#tion libr#ry th#t u!e! li!t! o' li!t! to repre!ent the >&3 to be gener#ted. I@ll t#l9 *ore ne.t ch#pter #bout u!ing con! cell! to repre!ent other d#t# !tructure!. Co**on i!p pro?ide! Fuite # l#rge libr#ry o' 'unction! 'or *#nipul#ting li!t!. In the !ection! H i!t3#nipul#tion /unction!H #nd H3#pping,H you@ll loo9 #t !o*e o' the *ore i*port#nt o' the!e 'unction!. >o6e?er, they 6ill be e#!ier to under!t#nd in the conte.t o' # 'e6 ide#! borro6ed 'ro* 'unction#l progr#**ing.
/ro* # 'unction#l point o' ?ie6, APPEND@! <ob i! to return the li!t 10#!#3#43 6ithout *odi'ying #ny o' the con! cell! in the li!t! 10#!3 #nd 13#43. 5ne ob?iou! 6#y to #chie?e th#t go#l i! to cre#te # co*pletely ne6 li!t con!i!ting o' 'our ne6 con! cell!. >o6e?er, th#t@! *ore 6or9 th#n i! nece!!#ry. In!te#d, APPEND #ctu#lly *#9e! only t6o ne6 con! cell! to hold the ?#lue! 0 #nd !, lin9ing the* together #nd pointing the CDR o' the !econd con! cell #t the he#d o' the l#!t #rgu*ent, the li!t 13#43. It then return! the con! cell cont#ining the 0. :one o' the origin#l con! cell! h#! been *odi'ied, #nd the re!ult i! indeed the li!t 10#!#3#43. &he only 6rin9le i! th#t the li!t returned by APPEND !h#re! !o*e con! cell! 6ith the li!t 13#43. &he re!ulting !tructure loo9! li9e thi!:
In gener#l, APPEND *u!t copy #ll but it! l#!t #rgu*ent, but it c#n #l6#y! return # re!ult th#t shares structure 6ith the l#!t #rgu*ent. 5ther 'unction! t#9e !i*il#r #d?#nt#ge o' li!t!@ #bility to !h#re !tructure. So*e, li9e APPEND, #re !peci'ied to #l6#y! return re!ult! th#t !h#re !tructure in # p#rticul#r 6#y. 5ther! #re !i*ply #llo6ed to return !h#red !tructure #t the di!cretion o' the i*ple*ent#tion.
-1estructi,e- 7perations
I' Co**on i!p 6ere # purely 'unction#l l#ngu#ge, th#t 6ould be the end o' the !tory. >o6e?er, bec#u!e it@! po!!ible to *odi'y # con! cell #'ter it h#! been cre#ted by SETFing it! CAR or CDR, you need to thin9 # bit #bout ho6 !ide e''ect! #nd !tructure !h#ring *i.. 7ec#u!e o' i!p@! 'unction#l herit#ge, oper#tion! th#t *odi'y e.i!ting ob<ect! #re c#lled destructive))in 'unction#l progr#**ing, ch#nging #n ob<ect@! !t#te Hde!troy!H it !ince it no longer repre!ent! the !#*e ?#lue. >o6e?er, u!ing the !#*e ter* to de!cribe #ll !t#te-*odi'ying oper#tion! le#d! to # cert#in #*ount o' con'u!ion !ince there #re t6o ?ery di''erent 9ind! o' de!tructi?e oper#tion!, for)side)effect oper#tion! #nd rec0cling oper#tion!.5 /or-!ide-e''ect oper#tion! #re tho!e u!ed !peci'ic#lly 'or their !ide e''ect!. %ll u!e! o' SETF #re de!tructi?e in thi! !en!e, #! #re 'unction! th#t u!e SETF under the co?er! to ch#nge the !t#te o' #n e.i!ting ob<ect !uch #! VECTOR-PUSH or VECTOR-POP. 7ut it@! # bit un'#ir to de!cribe the!e oper#tion! #! de!tructi?e--they@re not intended to be u!ed in code 6ritten in # 'unction#l !tyle, !o they !houldn@t be de!cribed u!ing 'unction#l ter*inology. >o6e?er, i' you *i. non'unction#l, 'or-!ide-e''ect oper#tion! 6ith 'unction! th#t return !tructure-!h#ring re!ult!, then you need to be c#re'ul not to in#d?ertently *odi'y the !h#red !tructure. /or in!t#nce, con!ider the!e three de'inition!:
1de(parameter#Ulist-0U#1list#0#!33 1de(parameter#Ulist-!U#1list#3#433 1de(parameter#Ulist-3U#1append#Ulist-0U#Ulist-!U33
%'ter e?#lu#ting the!e 'or*!, you h#?e three li!t!, but Ulist-3U #nd Ulist-!U !h#re !tructure <u!t li9e the li!t! in the pre?iou! di#gr#*.
Ulist-0U##################==/#10#!3 Ulist-!U##################==/#13#43 Ulist-3U##################==/#10#!#3#43
&he ch#nge to Ulist-!U #l!o ch#nge! Ulist-3U bec#u!e o' the !h#red !tructure: the 'ir!t con! cell in Ulist-!U i! #l!o the third con! cell in Ulist-3U. SETFing the FIRST o' Ulist-!U ch#nge! the ?#lue in the CAR o' th#t con! cell, #''ecting both li!t!.
5n the other h#nd, the other 9ind o' de!tructi?e oper#tion!, recycling oper#tion!, are intended to be u!ed in 'unction#l code. &hey u!e !ide e''ect! only #! #n opti*iA#tion. In p#rticul#r, they reu!e cert#in con! cell! 'ro* their #rgu*ent! 6hen building their re!ult. >o6e?er, unli9e 'unction! !uch #! APPEND th#t reu!e con! cell! by including the*, un*odi'ied, in the li!t they return, recycling 'unction! reu!e con! cell! #! r#6 *#teri#l, *odi'ying the CAR #nd CDR #! nece!!#ry to build the de!ired re!ult. &hu!, recycling 'unction! c#n be u!ed !#'ely only 6hen the origin#l li!t! #ren@t going to be needed #'ter the c#ll to the recycling 'unction. &o !ee ho6 # recycling 'unction 6or9!, let@! co*p#re REVERSE, the nonde!tructi?e 'unction th#t return! # re?er!ed ?er!ion o' # !eFuence, to NREVERSE, # recycling ?er!ion o' the !#*e 'unction. 7ec#u!e REVERSE doe!n@t *odi'y it! #rgu*ent, it *u!t #lloc#te # ne6 con! cell 'or e#ch ele*ent in the li!t being re?er!ed. 7ut !uppo!e you 6rite !o*ething li9e thi!:
1set(#UlistU#1reverse#UlistU33
7y #!!igning the re!ult o' REVERSE b#c9 to UlistU, you@?e re*o?ed the re'erence to the origin#l ?#lue o' UlistU. %!!u*ing the con! cell! in the origin#l li!t #ren@t re'erenced #ny6here el!e, they@re no6 eligible to be g#rb#ge collected. >o6e?er, in *#ny i!p i*ple*ent#tion! it@d be *ore e''icient to i**edi#tely reu!e the e.i!ting con! cell! r#ther th#n #lloc#ting ne6 one! #nd letting the old one! beco*e g#rb#ge. NREVERSE #llo6! you to do e.#ctly th#t. &he 2 !t#nd! 'or non)consing, *e#ning it doe!n@t need to #lloc#te #ny ne6 con! cell!. &he e.#ct !ide e''ect! o' NREVERSE #re intention#lly not !peci'ied--it@! #llo6ed to *odi'y #ny CAR or CDR o' #ny con! cell in the li!t--but # typic#l i*ple*ent#tion *ight 6#l9 do6n the li!t ch#nging the CDR o' e#ch con! cell to point to the pre?iou! con! cell, e?entu#lly returning the con! cell th#t 6#! pre?iou!ly the l#!t con! cell in the old li!t #nd i! no6 the he#d o' the re?er!ed li!t. :o ne6 con! cell! need to be #lloc#ted, #nd no g#rb#ge i! cre#ted. 3o!t recycling 'unction!, li9e NREVERSE, h#?e nonde!tructi?e counterp#rt! th#t co*pute the !#*e re!ult. In gener#l, the recycling 'unction! h#?e n#*e! th#t #re the !#*e #! their non-de!tructi?e counterp#rt! e.cept 6ith # le#ding 2. >o6e?er, not #ll do, including !e?er#l o' the *ore co**only u!ed recycling 'unction! !uch #! NCONC, the recycling ?er!ion o' APPEND, #nd DELETE, DELETEIF, DELETE-IF-NOT, #nd DELETE-DUPLICATES, the recycling ?er!ion! o' the REMOVE '#*ily o' !eFuence 'unction!. In gener#l, you u!e recycling 'unction! in the !#*e 6#y you u!e their nonde!tructi?e counterp#rt! e.cept it@! !#'e to u!e the* only 6hen you 9no6 the #rgu*ent! #ren@t going to be u!ed #'ter the 'unction return!. &he !ide e''ect! o' *o!t recycling 'unction! #ren@t !peci'ied tightly enough to be relied upon. >o6e?er, the 6#ter! #re 'urther *uddied by # h#nd'ul o' recycling 'unction! 6ith !peci'ied !ide e''ect! th#t can be relied upon. &hey #re NCONC, the recycling ?er!ion o' APPEND, #nd NSUBSTITUTE #nd it! -9E #nd -9E-8;F ?#ri#nt!, the recycling ?er!ion! o' the !eFuence 'unction! SUBSTITUTE #nd 'riend!. i9e APPEND, NCONC return! # conc#ten#tion o' it! li!t #rgu*ent!, but it build! it! re!ult in the 'ollo6ing 6#y: 'or e#ch none*pty li!t it@! p#!!ed, NCONC !et! the CDR o' the li!t@! l#!t con! cell to point to the 'ir!t con! cell o' the ne.t none*pty li!t. It then return! the 'ir!t li!t, 6hich i! no6 the he#d o' the !pliced-together re!ult. &hu!:
1de(parameter#U)U#1list#0#!#333 1nconc#U)U#1list#4#"#633#==/#10#!#3#4#"#63
U)U#==/#10#!#3#4#"#63
NSUBSTITUTE #nd ?#ri#nt! c#n be relied on to 6#l9 do6n the li!t !tructure o' the li!t #rgu*ent #nd to SETF the CAR! o' #ny con! cell! holding the old ?#lue to the ne6 ?#lue #nd to other6i!e le#?e the li!t int#ct. It then return! the origin#l li!t, 6hich no6 h#! the !#*e ?#lue #! 6ould@?e been co*puted by SUBSTITUTE. 0 &he 9ey thing to re*e*ber #bout NCONC #nd NSUBSTITUTE i! th#t they@re the e.ception! to the rule th#t you c#n@t rely on the !ide e''ect! o' recycling 'unction!. It@! per'ectly #ccept#ble--#nd #rgu#bly good !tyle--to ignore the reli#bility o' their !ide e''ect! #nd u!e the*, li9e #ny other recycling 'unction, only 'or the ?#lue they return.
&he ne.t *o!t co**on recycling idio*) i! to i**edi#tely re#!!ign the ?#lue returned by the recycling 'unction b#c9 to the pl#ce cont#ining the potenti#lly recycled ?#lue. /or in!t#nce, you@ll o'ten !ee e.pre!!ion! li9e the 'ollo6ing, u!ing DELETE, the recycling ?er!ion o' REMOVE:
1set(#(oo#1delete#nil#(oo33
&hi! !et! the ?#lue o' (oo to it! old ?#lue e.cept 6ith #ll the NIL! re*o?ed. >o6e?er, e?en thi! idio* *u!t be u!ed 6ith !o*e c#re--i' (oo !h#re! !tructure 6ith li!t! re'erenced el!e6here, u!ing DELETE
in!te#d o' REMOVE c#n de!troy the !tructure o' tho!e other li!t!. /or e.#*ple, con!ider the t6o li!t! Ulist-!U #nd Ulist-3U 'ro* e#rlier th#t !h#re their l#!t t6o con! cell!.
Ulist-!U#==/#1 #43 Ulist-3U#==/#10#!# #43
>o6e?er, DELETE 6ill li9ely per'or* the nece!!#ry deletion by !etting the CDR o' the third con! cell to NIL, di!connecting the 'ourth con! cell, the one holding the 4, 'ro* the li!t. 7ec#u!e the third con! cell o' Ulist-3U i! #l!o the 'ir!t con! cell in Ulist-!U, the 'ollo6ing *odi'ie! Ulist-!U #! 6ell:
Ulist-!U#==/#1 3
I' you h#d u!ed REMOVE in!te#d o' DELETE, it 6ould@?e built # li!t cont#ining the ?#lue! 0, !, #nd , cre#ting ne6 con! cell! #! nece!!#ry r#ther th#n *odi'ying #ny o' the con! cell! in Ulist-3U. In th#t c#!e, Ulist-!U 6ouldn@t h#?e been #''ected. &he PUSH;NREVERSE #nd SETF;DELETE idio*! prob#bly #ccount 'or ,0 percent o' the u!e! o' recycling 'unction!. 5ther u!e! #re po!!ible but reFuire 9eeping c#re'ul tr#c9 o' 6hich 'unction! return !h#red !tructure #nd 6hich do not. In gener#l, 6hen *#nipul#ting li!t!, it@! be!t to 6rite your o6n code in # 'unction#l !tyle--your 'unction! !hould depend only on the content! o' their li!t #rgu*ent! #nd !houldn@t *odi'y the*. /ollo6ing th#t rule 6ill, o' cour!e, rule out u!ing #ny de!tructi?e 'unction!, recycling or other6i!e. 5nce you h#?e your code 6or9ing, i' pro'iling !ho6! you need to opti*iAe, you c#n repl#ce nonde!tructi?e li!t oper#tion! 6ith their recycling counterp#rt! but only i' you@re cert#in the #rgu*ent li!t! #ren@t re'erenced 'ro* #ny6here el!e. 5ne l#!t gotch# to 6#tch out 'or i! th#t the !orting 'unction! SORT, STABLE-SORT, #nd MERGE *entioned in Ch#pter 11 #re #l!o recycling 'unction! 6hen #pplied to li!t!.10 >o6e?er, the!e 'unction! don@t h#?e nonde!tructi?e counterp#rt!, !o i' you need to !ort # li!t 6ithout de!troying it, you need to p#!! the !orting 'unction # copy *#de 6ith COPY-LIST. In either c#!e you need to be !ure to !#?e the re!ult o' the !orting 'unction bec#u!e the origin#l #rgu*ent i! li9ely to be in t#tter!. /or in!t#nce:
$L-+,-./#1de(parameter#UlistU#1list#4#3#!#033 UL9,FU $L-+,-./#1sort#UlistU#NCO3 10#!#3#43######################S#loo&s#good $L-+,-./#UlistU 143############################S#whoopsA
List4+anipu%ation Functions
With th#t b#c9ground out o' the 6#y, you@re re#dy to loo9 #t the libr#ry o' 'unction! Co**on i!p pro?ide! 'or *#nipul#ting li!t!. 4ou@?e #lre#dy !een the b#!ic 'unction! 'or getting #t the ele*ent! o' # li!t: FIRST #nd REST. %lthough you c#n get #t #ny ele*ent o' # li!t by co*bining enough c#ll! to REST Bto *o?e do6n the li!tC 6ith # FIRST Bto e.tr#ct the ele*entC, th#t c#n be # bit tediou!. So Co**on i!p pro?ide!
'unction! n#*ed 'or the other ordin#l! 'ro* SECOND to TENTH th#t return the #ppropri#te ele*ent. 3ore gener#lly, the 'unction NTH t#9e! t6o #rgu*ent!, #n inde. #nd # li!t, #nd return! the nth BAerob#!edC ele*ent o' the li!t. Si*il#rly, NTHCDR t#9e! #n inde. #nd # li!t #nd return! the re!ult o' c#lling CDR n ti*e!. B&hu!, 1nthcdr# #...3 !i*ply return! the origin#l li!t, #nd 1nthcdr#0#...3 i! eFui?#lent to REST.C :ote, ho6e?er, th#t none o' the!e 'unction! i! #ny *ore e''icient, in ter*! o' 6or9 done by the co*puter, th#n the eFui?#lent co*bin#tion! o' FIRST! #nd REST!--there@! no 6#y to get to the nth ele*ent o' # li!t 6ithout 'ollo6ing n CDR re'erence!.11 &he 2, co*po!ite CAR;CDR 'unction! #re #nother '#*ily o' 'unction! you *#y !ee u!ed 'ro* ti*e to ti*e. (#ch 'unction i! n#*ed by pl#cing # !eFuence o' up to 'our I! #nd <! bet6een # $ #nd ., 6ith e#ch I repre!enting # c#ll to CAR #nd e#ch < # c#ll to CDR. &hu!:
1caar#list3#===#1car#1car#list33 1cadr#list3#===#1car#1cdr#list33 1cadadr#list3#===#1car#1cdr#1car#1cdr#list3333
:ote, ho6e?er, th#t *#ny o' the!e 'unction! *#9e !en!e only 6hen #pplied to li!t! th#t cont#in other li!t!. /or in!t#nce, CAAR e.tr#ct! the CAR o' the CAR o' the li!t it@! gi?enG thu!, the li!t it@! p#!!ed *u!t cont#in #nother li!t #! it! 'ir!t ele*ent. In other 6ord!, the!e #re re#lly 'unction! on tree! r#ther th#n li!t!:
1caar#1list#0#!#333##################==/#error 1caar#1list#1list#0#!3#333###########==/#0 1cadr#1list#1list#0#!3#1list#3#4333##==/#13#43 1caadr#1list#1list#0#!3#1list#3#4333#==/#3
&he!e 'unction! #ren@t u!ed #! o'ten no6 #! in the old d#y!. %nd e?en the *o!t die-h#rd old-!chool i!p h#c9er! tend to #?oid the longer co*bin#tion!. >o6e?er, they@re u!ed Fuite # bit in older i!p code, !o it@! 6orth #t le#!t under!t#nding ho6 they 6or9.12 &he FIRST-TENTH #nd CAR, CADR, #nd !o on, 'unction! c#n #l!o be u!ed #! SETF#ble pl#ce! i' you@re u!ing li!t! non'unction#lly. &#ble 12-1 !u**#riAe! !o*e other li!t 'unction! th#t I 6on@t co?er in det#il. &#ble 12-1. 5ther i!t /unction! /unction LAST +e!cription $eturn! the l#!t con! cell in # li!t. With #n integer, #rgu*ent return! the l#!t n con! cell!. $eturn! # copy o' the li!t, e.cluding the l#!t con! cell. With #n integer #rgu*ent, BUTLAST e.clude! the l#!t n cell!. &he recycling ?er!ion o' BUTLASTG *#y *odi'y #nd return the #rgu*ent li!t but h#! no NBUTLAST reli#ble !ide e''ect!. LDIFF $eturn! # copy o' # li!t up to # gi?en con! cell. TAILP $eturn! true i' # gi?en ob<ect i! # con! cell th#t@! p#rt o' the !tructure o' # li!t. 7uild! # li!t to hold #ll but the l#!t o' it! #rgu*ent! #nd then *#9e! the l#!t #rgu*ent LIST* the CDR o' the l#!t cell in the li!t. In other 6ord!, # cro!! bet6een LIST #nd APPEND. 7uild! #n n ite* li!t. &he initi#l ele*ent! o' the li!t #re NIL or the ?#lue !peci'ied 6ith MA+E-LIST the :initial-element 9ey6ord #rgu*ent. Co*bin#tion o' REVERSE #nd APPENDG re?er!e! 'ir!t #rgu*ent #! 6ith REVERSE #nd REVAPPEND then #ppend! the !econd #rgu*ent.
$ecycling ?er!ion o' REVAPPENDG re?er!e! 'ir!t #rgu*ent #! i' by NREVERSE #nd then #ppend! the !econd #rgu*ent. :o reli#ble !ide e''ect!. Predic#te to te!t 6hether #n ob<ect i! # con! cell. Predic#te to te!t 6hether #n ob<ect i! not # con! cell. Predic#te to te!t 6hether #n ob<ect i! either # con! cell or NIL. Predic#te to te!t 6hether #n ob<ect i! NIL. /unction#lly eFui?#lent to NOT but !tyli!tic#lly pre'er#ble 6hen te!ting 'or #n e*pty li!t #! oppo!ed to boole#n '#l!e.
+apping
%nother i*port#nt #!pect o' the 'unction#l !tyle i! the u!e o' higher-order 'unction!, 'unction! th#t t#9e other 'unction! #! #rgu*ent! or return 'unction! #! ?#lue!. 4ou !#6 !e?er#l e.#*ple! o' higher-order 'unction!, !uch #! MAP, in the pre?iou! ch#pter. %lthough MAP c#n be u!ed 6ith both li!t! #nd ?ector! Bth#t i!, 6ith #ny 9ind o' !eFuenceC, Co**on i!p #l!o pro?ide! !i. *#pping 'unction! !peci'ic#lly 'or li!t!. &he di''erence! bet6een the !i. 'unction! h#?e to do 6ith ho6 they build up their re!ult #nd 6hether they #pply the 'unction to the ele*ent! o' the li!t or to the con! cell! o' the li!t !tructure. MAPCAR i! the 'unction *o!t li9e MAP. 7ec#u!e it #l6#y! return! # li!t, it doe!n@t reFuire the re!ulttype #rgu*ent MAP doe!. In!te#d, it! 'ir!t #rgu*ent i! the 'unction to #pply, #nd !ub!eFuent #rgu*ent! #re the li!t! 6ho!e ele*ent! 6ill pro?ide the #rgu*ent! to the 'unction. 5ther6i!e, it beh#?e! li9e MAP: the 'unction i! #pplied to !ucce!!i?e ele*ent! o' the li!t #rgu*ent!, t#9ing one ele*ent 'ro* e#ch li!t per #pplic#tion o' the 'unction. &he re!ult! o' e#ch 'unction c#ll #re collected into # ne6 li!t. /or e.#*ple:
1mapcar#NC1lambda#1)3#1U#!#)33#1list#0#!#333#==/#1!#4#63 1mapcar#NC2#1list#0#!#33#1list#0 #! #3 33#==/#100#!!#333
MAPLIST i! <u!t li9e MAPCAR e.cept in!te#d o' p#!!ing the ele*ent! o' the li!t to the 'unction, it p#!!e! the #ctu#l con! cell!.13 &hu!, the 'unction h#! #cce!! not only to the ?#lue o' e#ch ele*ent o' the li!t B?i# the CAR o' the con! cellC but #l!o to the re!t o' the li!t B?i# the CDRC. MAPCAN #nd MAPCON 6or9 li9e MAPCAR #nd MAPLIST e.cept 'or the 6#y they build up their re!ult. While MAPCAR #nd MAPLIST build # co*pletely ne6 li!t to hold the re!ult! o' the 'unction c#ll!, MAPCAN #nd MAPCON build their re!ult by !plicing together the re!ult!--6hich *u!t be li!t!--#! i' by NCONC. &hu!, e#ch 'unction in?oc#tion c#n pro?ide #ny nu*ber o' ele*ent! to be included in the re!ult.1- MAPCAN, li9e MAPCAR, p#!!e! the ele*ent! o' the li!t to the *#pped 'unction 6hile MAPCON, li9e MAPLIST, p#!!e! the con! cell!. /in#lly, the 'unction! MAPC #nd MAPL #re control con!truct! di!gui!ed #! 'unction!--they !i*ply return their 'ir!t li!t #rgu*ent, !o they@re u!e'ul only 6hen the !ide e''ect! o' the *#pped 'unction do !o*ething intere!ting. MAPC i! the cou!in o' MAPCAR #nd MAPCAN 6hile MAPL i! in the MAPLIST;MAPCON '#*ily.
7ther /tructures
While con! cell! #nd li!t! #re typic#lly con!idered to be !ynony*ou!, th#t@! not Fuite right--#! I *entioned e#rlier, you c#n u!e li!t! o' li!t! to repre!ent tree!. Du!t #! the 'unction! di!cu!!ed in thi! ch#pter #llo6 you to tre#t !tructure! built out o' con! cell! #! li!t!, other 'unction! #llo6 you to u!e con! cell! to repre!ent tree!, !et!, #nd t6o 9ind! o' 9ey;?#lue *#p!. I@ll di!cu!! !o*e o' tho!e 'unction! in the ne.t ch#pter.
the pl#ce gi?en to SETF i! # CAR or CDR, it e.p#nd! into # c#ll to the 'unction RPLACA or RPLACDG !o*e old-!chool i!per!--the !#*e one! 6ho !till u!e SETQ--6ill !till u!e RPLACA #nd RPLACD directly, but *odern !tyle i! to u!e SETF o' CAR or CDR.
-&ypic#lly,
!i*ple ob<ect! !uch #! nu*ber! #re dr#6n 6ithin the #ppropri#te bo., #nd *ore co*ple. ob<ect! 6ill be dr#6n out!ide the bo. 6ith #n #rro6 'ro* the bo. indic#ting the re'erence. &hi! #ctu#lly corre!pond! 6ell 6ith ho6 *#ny Co**on i!p i*ple*ent#tion! 6or9--#lthough #ll ob<ect! #re conceptu#lly !tored by re'erence, cert#in !i*ple i**ut#ble ob<ect! c#n be !tored directly in # con! cell.
5&he
phr#!e for)side)effect i! u!ed in the l#ngu#ge !t#nd#rd, but rec0cling i! *y o6n in?entionG *o!t i!p liter#ture !i*ply u!e! the ter* destructive 'or both 9ind! o' oper#tion!, le#ding to the con'u!ion I@* trying to di!pel.
0&he
!tring 'unction! NSTRING-CAPITALI3E, NSTRING-DOWNCASE, #nd NSTRING-UPCASE #re !i*il#r--they return the !#*e re!ult! #! their :-le!! counterp#rt! but #re !peci'ied to *odi'y their !tring #rgu*ent in pl#ce.
2/or
e.#*ple, in #n e.#*in#tion o' #ll u!e! o' recycling 'unction! in the Co**on i!p 5pen Code Collection BC 5CCC, # di?er!e !et o' libr#rie! 6ritten by ?#riou! #uthor!, in!t#nce! o' the PUSH;NREVERSE idio* #ccounted 'or ne#rly h#l' o' #ll u!e! o' recycling 'unction!.
,&here
#re, o' cour!e, other 6#y! to do thi! !#*e thing. &he e.tended LOOP *#cro, 'or in!t#nce, *#9e! it p#rticul#rly e#!y #nd li9ely gener#te! code th#t@! e?en *ore e''icient th#n the PUSH; NREVERSE ?er!ion.
)&hi!
idio* #ccount! 'or 30 percent o' u!e! o' recycling in the C 5CC code b#!e.
10SORT
#nd STABLE-SORT c#n be u!ed #! 'or-!ide-e''ect oper#tion! on ?ector!, but !ince they !till return the !orted ?ector, you !hould ignore th#t '#ct #nd u!e the* 'or return ?#lue! 'or the !#9e o' con!i!tency.
11NTH
i! roughly eFui?#lent to the !eFuence 'unction ELT but 6or9! only 6ith li!t!. %l!o, con'u!ingly, NTH t#9e! the inde. #! the 'ir!t #rgu*ent, the oppo!ite o' ELT. %nother di''erence i! th#t ELT 6ill !ign#l #n error i' you try to #cce!! #n ele*ent #t #n inde. gre#ter th#n or eFu#l to the length o' the li!t, but NTH 6ill return NIL.
12In
p#rticul#r, they u!ed to be u!ed to e.tr#ct the ?#riou! p#rt! o' e.pre!!ion! p#!!ed to *#cro! be'ore the in?ention o' de!tructuring p#r#*eter li!t!. /or e.#*ple, you could t#9e #p#rt the 'ollo6ing e.pre!!ion:
1when#1/#)#0 3#1print#)33
i9e thi!:
SS#the#condition 1cadr#C1when#1/#)#0 3#1print#)333#==/#1/#[#0 3 SS#the#bod?5#as#a#list 1cddr#C1when#1/#)#0 3#1print#)333#==/#11T.98F#[33
13
&hu!, MAPLIST i! the *ore pri*iti?e o' the t6o 'unction!--i' you h#d only MAPLIST, you could build MAPCAR on top o' it, but you couldn@t build MAPLIST on top o' MAPCAR.
1-In
i!p di#lect! th#t didn@t h#?e 'iltering 'unction! li9e REMOVE, the idio*#tic 6#y to 'ilter # li!t 6#! 6ith MAPCAN.
1mapcan#NC1lambda#1)3#1i(#1=#)#0 3#nil#1list#)333##list3#===#1remove#0 #list3
Trees
&re#ting !tructure! built 'ro* con! cell! #! tree! i! <u!t #bout #! n#tur#l #! tre#ting the* #! li!t!. Wh#t i! # li!t o' li!t!, #'ter #ll, but #nother 6#y o' thin9ing o' # tree" &he di''erence bet6een # 'unction th#t tre#t! # bunch o' con! cell! #! # li!t #nd # 'unction th#t tre#t! the !#*e bunch o' con! cell! #! # tree h#! to do 6ith 6hich con! cell! the 'unction! tr#?er!e to 'ind the ?#lue! o' the li!t or tree. &he con! cell!
tr#?er!ed by # li!t 'unction, c#lled the list structure, #re 'ound by !t#rting #t the 'ir!t con! cell #nd 'ollo6ing CDR re'erence! until re#ching # NIL. &he ele*ent! o' the li!t #re the ob<ect! re'erenced by the CAR! o' the con! cell! in the li!t !tructure. I' # con! cell in the li!t !tructure h#! # CAR th#t re'erence! #nother con! cell, the re'erenced con! cell i! con!idered to be the he#d o' # li!t th#t@! #n ele*ent o' the outer li!t.1 Tree structure, on the other h#nd, i! tr#?er!ed by 'ollo6ing both CAR #nd CDR re'erence! 'or #! long #! they point to other con! cell!. &he ?#lue! in # tree #re thu! the #to*ic-non-con!-cell-?#lue! re'erenced by either the CAR! or the CDR! o' the con! cell! in the tree !tructure. /or in!t#nce, the 'ollo6ing bo.-#nd-#rro6 di#gr#* !ho6! the con! cell! th#t *#9e up the li!t o' li!t!: 110#!3#13#43#1"#633. &he li!t !tructure include! only the three con! cell! in!ide the d#!hed bo. 6hile the tree !tructure include! #ll the con! cell!.
&o !ee the di''erence bet6een # li!t 'unction #nd # tree 'unction, you c#n con!ider ho6 the 'unction! COPY-LIST #nd COPY-TREE 6ill copy thi! bunch o' con! cell!. COPY-LIST, #! # li!t 'unction, copie! the con! cell! th#t *#9e up the li!t !tructure. &h#t i!, it *#9e! # ne6 con! cell corre!ponding to e#ch o' the con! cell! in!ide the d#!hed bo.. &he CAR! o' e#ch o' the!e ne6 con! cell! re'erence the !#*e ob<ect #! the CAR! o' the origin#l con! cell! in the li!t !tructure. &hu!, COPY-LIST doe!n@t copy the !ubli!t! 10#!3, 13#43, or 1"#63, #! !ho6n in thi! di#gr#*:
COPY-TREE, on the other h#nd, *#9e! # ne6 con! cell 'or e#ch o' the con! cell! in the di#gr#* #nd lin9! the* together in the !#*e !tructure, #! !ho6n in thi! di#gr#*:
Where # con! cell in the origin#l re'erenced #n #to*ic ?#lue, the corre!ponding con! cell in the copy 6ill re'erence the !#*e ?#lue. &hu!, the only ob<ect! re'erenced in co**on by the origin#l tree #nd the copy produced by COPY-TREE #re the nu*ber! 5, 0, #nd the !y*bol NIL. %nother 'unction th#t 6#l9! both the CAR! #nd the CDR! o' # tree o' con! cell! i! TREE-EQUAL, 6hich co*p#re! t6o tree!, con!idering the* eFu#l i' the tree !tructure i! the !#*e !h#pe #nd i' the le#?e! #re EQL Bor i' they !#ti!'y the te!t !upplied 6ith the :test 9ey6ord #rgu*entC. So*e other tree-centric 'unction! #re the tree #n#log! to the SUBSTITUTE #nd NSUBSTITUTE !eFuence 'unction! #nd their -9E #nd -9E-8;F ?#ri#nt!. &he 'unction SUBST, li9e SUBSTITUTE, t#9e! # ne6 ite*, #n old ite*, #nd # tree B#! oppo!ed to # !eFuenceC, #long 6ith :&e? #nd :test 9ey6ord #rgu*ent!, #nd it return! # ne6 tree 6ith the !#*e !h#pe #! the origin#l tree but 6ith #ll in!t#nce! o' the old ite* repl#ced 6ith the ne6 ite*. /or e.#*ple:
$L-+,-./#1s'bst#0 #0#C10#!#13#!#03#110#03#1!#!3333 10 #!#13#!#0 3#110 #0 3#1!#!333
SUBST-IF i! #n#logou! to SUBSTITUTE-IF. In!te#d o' #n old ite*, it t#9e! # one-#rgu*ent 'unction--the 'unction i! c#lled 6ith e#ch #to*ic ?#lue in the tree, #nd 6hene?er it return! true, the po!ition in the ne6 tree i! 'illed 6ith the ne6 ?#lue. SUBST-IF-NOT i! the !#*e e.cept the ?#lue! 6here the te!t return! NIL #re repl#ced. NSUBST, NSUBST-IF, #nd NSUBST-IF-NOT #re the recycling ?er!ion! o' the SUBST 'unction!. %! 6ith *o!t other recycling 'unction!, you !hould u!e the!e 'unction! only #! drop-in repl#ce*ent! 'or their nonde!tructi?e counterp#rt! in !itu#tion! 6here you 9no6 there@! no d#nger o' *odi'ying # !h#red !tructure. In p#rticul#r, you *u!t continue to !#?e the return ?#lue o' the!e 'unction! !ince you h#?e no gu#r#ntee th#t the re!ult 6ill be EQ to the origin#l tree.2
/ets
Set! c#n #l!o be i*ple*ented in ter*! o' con! cell!. In '#ct, you c#n tre#t #ny li!t #! # !et--Co**on i!p pro?ide! !e?er#l 'unction! 'or per'or*ing !et-theoretic oper#tion! on li!t!. >o6e?er, you !hould be#r in *ind th#t bec#u!e o' the 6#y li!t! #re !tructured, the!e oper#tion! get le!! #nd le!! e''icient the bigger the !et! get. &h#t !#id, u!ing the built-in !et 'unction! *#9e! it e#!y to 6rite !et-*#nipul#tion code. %nd 'or !*#ll !et! they *#y 6ell be *ore e''icient th#n the #ltern#ti?e!. I' pro'iling !ho6! you th#t the!e 'unction! #re # per'or*#nce bottlenec9 in your code, you c#n #l6#y! repl#ce the li!t! 6ith !et! built on top o' h#!h t#ble! or bit ?ector!. &o build up # !et, you c#n u!e the 'unction AD4OIN. AD4OIN t#9e! #n ite* #nd # li!t repre!enting # !et #nd return! # li!t repre!enting the !et cont#ining the ite* #nd #ll the ite*! in the origin#l !et. &o deter*ine 6hether the ite* i! pre!ent, it *u!t !c#n the li!tG i' the ite* i!n@t 'ound, AD4OIN cre#te! # ne6 con! cell holding the ite* #nd pointing to the origin#l li!t #nd return! it. 5ther6i!e, it return! the origin#l li!t. AD4OIN #l!o t#9e! :&e? #nd :test 9ey6ord #rgu*ent!, 6hich #re u!ed 6hen deter*ining 6hether the ite* i! pre!ent in the origin#l li!t. i9e CONS, AD4OIN h#! no e''ect on the origin#l li!t--i' you 6#nt to *odi'y # p#rticul#r li!t, you need to #!!ign the ?#lue returned by AD4OIN to the pl#ce 6here the li!t c#*e 'ro*. &he *odi'y *#cro PUSHNEW doe! thi! 'or you #uto*#tic#lly.
$L-+,-./#1de(parameter#UsetU#133 U,-FU $L-+,-./#1adjoin#0#UsetU3
103 $L-+,-./#UsetU 89L $L-+,-./#1set(#UsetU#1adjoin#0#UsetU33 103 $L-+,-./#1p'shnew#!#UsetU3 1!#03 $L-+,-./#UsetU 1!#03 $L-+,-./#1p'shnew#!#UsetU3 1!#03
4ou c#n te!t 6hether # gi?en ite* i! in # !et 6ith MEMBER #nd the rel#ted 'unction! MEMBER-IF #nd MEMBER-IF-NOT. &he!e 'unction! #re !i*il#r to the !eFuence 'unction! FIND, FIND-IF, #nd FIND-IF-NOT e.cept they c#n be u!ed only 6ith li!t!. %nd in!te#d o' returning the ite* 6hen it@! pre!ent, they return the con! cell cont#ining the ite*--in other 6ord!, the !ubli!t !t#rting 6ith the de!ired ite*. When the de!ired ite* i!n@t pre!ent in the li!t, #ll three 'unction! return NIL. &he re*#ining !et-theoretic 'unction! pro?ide bul9 oper#tion!: INTERSECTION, UNION, SETDIFFERENCE, #nd SET-EXCLUSIVE-OR. (#ch o' the!e 'unction! t#9e! t6o li!t! #nd :&e? #nd :test 9ey6ord #rgu*ent! #nd return! # ne6 li!t repre!enting the !et re!ulting 'ro* per'or*ing the #ppropri#te !et-theoretic oper#tion on the t6o li!t!: INTERSECTION return! # li!t cont#ining #ll the ele*ent! 'ound in both #rgu*ent!. UNION return! # li!t cont#ining one in!t#nce o' e#ch uniFue ele*ent 'ro* the t6o #rgu*ent!.3 SET-DIFFERENCE return! # li!t cont#ining #ll the ele*ent! 'ro* the 'ir!t #rgu*ent th#t don@t #ppe#r in the !econd #rgu*ent. %nd SET-EXCLUSIVE-OR return! # li!t cont#ining tho!e ele*ent! #ppe#ring in only one or the other o' the t6o #rgu*ent li!t! but not in both. (#ch o' the!e 'unction! #l!o h#! # recycling counterp#rt 6ho!e n#*e i! the !#*e e.cept 6ith #n 2 pre'i.. /in#lly, the 'unction SUBSETP t#9e! t6o li!t! #nd the u!u#l :&e? #nd :test 9ey6ord #rgu*ent! #nd return! true i' the 'ir!t li!t i! # !ub!et o' the !econd--i' e?ery ele*ent in the 'ir!t li!t i! #l!o pre!ent in the !econd li!t. &he order o' the ele*ent! in the li!t! doe!n@t *#tter.
$L-+,-./#1s'bsetp#C13#!#03#C10#!#3#433 F $L-+,-./#1s'bsetp#C10#!#3#43#C13#!#033 89L
in!t#nce, the 'ollo6ing i! # bo.-#nd-#rro6 di#gr#* o' #n #li!t *#pping the !y*bol I to the nu*ber 1, L to 2, #nd $ to 3:
8nle!! the ?#lue in the CDR i! # li!t, con! cell! repre!enting the 9ey;?#lue p#ir! 6ill be dotted pairs in !-e.pre!!ion not#tion. &he #li!t di#gr#*ed in the pre?iou! 'igure, 'or in!t#nce, i! printed li9e thi!:
11I#.#03#1L#.#!3#1$#.#333
&he *#in loo9up 'unction 'or #li!t! i! ASSOC, 6hich t#9e! # 9ey #nd #n #li!t #nd return! the 'ir!t con! cell 6ho!e CAR *#tche! the 9ey or NIL i' no *#tch i! 'ound.
$L-+,-./#1assoc#Ca#C11a#.#03#1b#.#!3#1c#.#3333 1I#.#03 $L-+,-./#1assoc#Cc#C11a#.#03#1b#.#!3#1c#.#3333 1$#.#33 $L-+,-./#1assoc#Cd#C11a#.#03#1b#.#!3#1c#.#3333 89L
&o get the ?#lue corre!ponding to # gi?en 9ey, you !i*ply p#!! the re!ult o' ASSOC to CDR.
$L-+,-./#1cdr#1assoc#Ca#C11a#.#03#1b#.#!3#1c#.#33333 0
7y de'#ult the 9ey gi?en i! co*p#red to the 9ey! in the #li!t u!ing EQL, but you c#n ch#nge th#t 6ith the !t#nd#rd co*bin#tion o' :&e? #nd :test 9ey6ord #rgu*ent!. /or in!t#nce, i' you 6#nted to u!e !tring 9ey!, you *ight 6rite thi!:
$L-+,-./#1assoc#4a4#C114a4#.#03#14b4#.#!3#14c4#.#333#:test#NCstring=3 14a4#.#03
Without !peci'ying :test to be STRING=, th#t ASSOC 6ould prob#bly return NIL bec#u!e t6o !tring! 6ith the !#*e content! #ren@t nece!!#rily EQL.
$L-+,-./#1assoc#4a4#C114a4#.#03#14b4#.#!3#14c4#.#3333 89L
7ec#u!e ASSOC !e#rche! the li!t by !c#nning 'ro* the 'ront o' the li!t, one 9ey;?#lue p#ir in #n #li!t c#n !h#do6 other p#ir! 6ith the !#*e 9ey l#ter in the li!t.
$L-+,-./#1assoc#Ca#C11a#.#0 3#1a#.#03#1b#.#!3#1c#.#3333 1I#.#0 3
4ou c#n #dd # p#ir to the 'ront o' #n #li!t 6ith CONS li9e thi!:
1cons#1cons#Cnew-&e?#Cnew-val'e3#alist3
>o6e?er, #! # con?enience, Co**on i!p pro?ide! the 'unction ACONS, 6hich let! you 6rite thi!:
1acons#Cnew-&e?#Cnew-val'e#alist3
i9e CONS, ACONS i! # 'unction #nd thu! c#n@t *odi'y the pl#ce holding the #li!t it@! p#!!ed. I' you
or thi!:
1p'sh#1cons#Cnew-&e?#Cnew-val'e3#alist3
5b?iou!ly, the ti*e it t#9e! to !e#rch #n #li!t 6ith ASSOC i! # 'unction o' ho6 deep in the li!t the *#tching p#ir i! 'ound. In the 6or!t c#!e, deter*ining th#t no p#ir *#tche! reFuire! ASSOC to !c#n e?ery ele*ent o' the #li!t. >o6e?er, !ince the b#!ic *ech#ni!* 'or #li!t! i! !o light6eight, 'or !*#ll t#ble! #n #li!t c#n outper'or* # h#!h t#ble. %l!o, #li!t! gi?e you *ore 'le.ibility in ho6 you do the loo9up. I #lre#dy *entioned th#t ASSOC t#9e! :&e? #nd :test 9ey6ord #rgu*ent!. When tho!e don@t !uit your need!, you *#y be #ble to u!e the ASSOC-IF #nd ASSOC-IF-NOT 'unction!, 6hich return the 'ir!t 9ey;?#lue p#ir 6ho!e CAR !#ti!'ie! Bor not, in the c#!e o' ASSOC-IF-NOTC the te!t 'unction p#!!ed in the pl#ce o' # !peci'ic ite*. %nd three 'unction!--RASSOC, RASSOC-IF, #nd RASSOC-IF-NOT--6or9 <u!t li9e the corre!ponding ASSOC 'unction! e.cept they u!e the ?#lue in the CDR o' e#ch ele*ent #! the 9ey, per'or*ing # re?er!e loo9up. &he 'unction COPY-ALIST i! !i*il#r to COPY-TREE e.cept, in!te#d o' copying the 6hole tree !tructure, it copie! only the con! cell! th#t *#9e up the li!t !tructure, plu! the con! cell! directly re'erenced 'ro* the CAR! o' tho!e cell!. In other 6ord!, the origin#l #li!t #nd the copy 6ill both cont#in the !#*e ob<ect! #! the 9ey! #nd ?#lue!, e?en i' tho!e 9ey! or ?#lue! h#ppen to be *#de up o' con! cell!. /in#lly, you c#n build #n #li!t 'ro* t6o !ep#r#te li!t! o' 9ey! #nd ?#lue! 6ith the 'unction PAIRLIS. &he re!ulting #li!t *#y cont#in the p#ir! either in the !#*e order #! the origin#l li!t! or in re?er!e order. /or e.#*ple, you *#y get thi! re!ult:
$L-+,-./#1pairlis#C1a#b#c3#C10#!#333 11$#.#33#1L#.#!3#1I#.#033
&he other 9ind o' loo9up t#ble i! the property li!t, or pli!t, 6hich you u!ed to repre!ent the ro6! in the d#t#b#!e in Ch#pter 3. Structur#lly # pli!t i! <u!t # regul#r li!t 6ith the 9ey! #nd ?#lue! #! #ltern#ting ?#lue!. /or in!t#nce, # pli!t *#pping I, L, #nd $, to 1, 2, #nd 3 i! !i*ply the li!t 1I#0#L#!#$#33. In bo.e!-#nd-#rro6! 'or*, it loo9! li9e thi!:
>o6e?er, pli!t! #re le!! 'le.ible th#n #li!t!. In '#ct, pli!t! !upport only one 'und#*ent#l loo9up oper#tion, the 'unction GETF, 6hich t#9e! # pli!t #nd # 9ey #nd return! the #!!oci#ted ?#lue or NIL i' the 9ey i!n@t 'ound. GETF #l!o t#9e! #n option#l third #rgu*ent, 6hich 6ill be returned in pl#ce o' NIL i' the 9ey i!n@t 'ound. 8nli9e ASSOC, 6hich u!e! EQL #! it! de'#ult te!t #nd #llo6! # di''erent te!t 'unction to be !upplied 6ith # :test #rgu*ent, GETF #l6#y! u!e! EQ to te!t 6hether the pro?ided 9ey *#tche! the 9ey! in the pli!t. Con!eFuently, you !hould ne?er u!e nu*ber! or ch#r#cter! #! 9ey! in # pli!tG #! you !#6 in Ch#pter -, the beh#?ior o' EQ 'or tho!e type! i! e!!enti#lly unde'ined. Pr#ctic#lly !pe#9ing, the 9ey! in
# pli!t #re #l*o!t #l6#y! !y*bol!, 6hich *#9e! !en!e !ince pli!t! 6ere 'ir!t in?ented to i*ple*ent !y*bolic Hpropertie!,H #rbitr#ry *#pping! bet6een n#*e! #nd ?#lue!. 4ou c#n u!e SETF 6ith GETF to !et the ?#lue #!!oci#ted 6ith # gi?en 9ey. SETF #l!o tre#t! GETF # bit !peci#lly in th#t the 'ir!t #rgu*ent to GETF i! tre#ted #! the pl#ce to *odi'y. &hu!, you c#n u!e SETF o' GETF to #dd # ne6 9ey;?#lue p#ir to #n e.i!ting pli!t.
$L-+,-./#1de(parameter#UplistU#133 UTL9,FU $L-+,-./#UplistU 89L $L-+,-./#1set(#1get(#UplistU#:a3#03 0 $L-+,-./#UplistU 1:I#03 $L-+,-./#1set(#1get(#UplistU#:a3#!3 ! $L-+,-./#UplistU 1:I#!3
&o re*o?e # 9ey;?#lue p#ir 'ro* # pli!t, you u!e the *#cro REMF, 6hich !et! the pl#ce gi?en #! it! 'ir!t #rgu*ent to # pli!t cont#ining #ll the 9ey;?#lue p#ir! e.cept the one !peci'ied. It return! true i' the gi?en 9ey 6#! #ctu#lly 'ound.
$L-+,-./#1rem(#UplistU#:a3 F $L-+,-./#UplistU 89L
i9e GETF, REMF #l6#y! u!e! EQ to co*p#re the gi?en 9ey to the 9ey! in the pli!t. Since pli!t! #re o'ten u!ed in !itu#tion! 6here you 6#nt to e.tr#ct !e?er#l propertie! 'ro* the !#*e pli!t, Co**on i!p pro?ide! # 'unction, GET-PROPERTIES, th#t *#9e! it *ore e''icient to e.tr#ct *ultiple ?#lue! 'ro* # !ingle pli!t. It t#9e! # pli!t #nd # li!t o' 9ey! to !e#rch 'or #nd return!, #! *ultiple ?#lue!, the 'ir!t 9ey 'ound, the corre!ponding ?#lue, #nd the he#d o' the li!t !t#rting 6ith the 'ound 9ey. &hi! #llo6! you to proce!! # property li!t, e.tr#cting the de!ired propertie!, 6ithout continu#lly re!c#nning 'ro* the 'ront o' the li!t. /or in!t#nce, the 'ollo6ing 'unction e''iciently proce!!e!--u!ing the hypothetic#l 'unction process-propert?--#ll the 9ey;?#lue p#ir! in # pli!t 'or # gi?en li!t o' 9ey!:
1de('n#process-properties#1plist#&e?s3 ##1loop#while#plist#do #######1m'ltiple-val'e-bind#1&e?#val'e#tail3#1get-properties#plist#&e?s3 #########1when#&e?#1process-propert?#&e?#val'e33 #########1set(#plist#1cddr#tail33333
&he l#!t !peci#l thing #bout pli!t! i! the rel#tion!hip they h#?e 6ith !y*bol!: e?ery !y*bol ob<ect h#! #n #!!oci#ted pli!t th#t c#n be u!ed to !tore in'or*#tion #bout the !y*bol. &he pli!t c#n be obt#ined ?i# the 'unction SYMBOL-PLIST. >o6e?er, you r#rely c#re #bout the 6hole pli!tG *ore o'ten you@ll u!e the 'unction! GET, 6hich t#9e! # !y*bol #nd # 9ey #nd i! !horth#nd 'or # GETF o' the !#*e 9ey in the !y*bol! SYMBOL-PLIST.
1get#Cs?mbol#C&e?3#===#1get(#1s?mbol-plist#Cs?mbol3#C&e?3
i9e GETF, GET i! SETF#ble, !o you c#n #tt#ch #rbitr#ry in'or*#tion to # !y*bol li9e thi!:
1set(#1get#Csome-s?mbol#Cm?-&e?3#4in(ormation43
&o re*o?e # property 'ro* # !y*bol@! pli!t, you c#n u!e either REMF o' SYMBOL-PLIST or the con?enience 'unction REMPROP.1remprop#Cs?mbol#C&e?3#===#1rem(#1s?mbol-plist#Cs?mbol#&e?33
7eing #ble to #tt#ch #rbitr#ry in'or*#tion to n#*e! i! Fuite h#ndy 6hen doing #ny 9ind o' !y*bolic progr#**ing. /or in!t#nce, one o' the *#cro! you@ll 6rite in Ch#pter 2- 6ill #tt#ch in'or*#tion to n#*e! th#t other in!t#nce! o' the !#*e *#cro! 6ill e.tr#ct #nd u!e 6hen gener#ting their e.p#n!ion!.
1!/TR'#T'RI:&4BI:1
5ne l#!t tool 'or !licing #nd dicing li!t! th#t I need to co?er !ince you@ll need it in l#ter ch#pter! i! the DESTRUCTURING-BIND *#cro. &hi! *#cro pro?ide! # 6#y to destructure #rbitr#ry li!t!, !i*il#r to the 6#y *#cro p#r#*eter li!t! c#n t#9e #p#rt their #rgu*ent li!t. &he b#!ic !9eleton o' # DESTRUCTURING-BIND i! #! 'ollo6!:
1destr'ct'ring-bind#1parameterU3#list ##body-formU3
&he p#r#*eter li!t c#n include #ny o' the type! o' p#r#*eter! !upported in *#cro p#r#*eter li!t! !uch #! &o !"o#$%, &&'(!, #nd &)'* p#r#*eter!.5 %nd, #! in *#cro p#r#*eter li!t!, #ny p#r#*eter c#n be repl#ced 6ith # ne!ted de!tructuring p#r#*eter li!t, 6hich t#9e! #p#rt the li!t th#t 6ould other6i!e h#?e been bound to the repl#ced p#r#*eter. &he list 'or* i! e?#lu#ted once #nd !hould return # li!t, 6hich i! then de!tructured #nd the #ppropri#te ?#lue! #re bound to the ?#ri#ble! in the p#r#*eter li!t. &hen the bod0)forms #re e?#lu#ted in order 6ith tho!e binding! in e''ect. So*e !i*ple e.#*ple! 'ollo6:
1destr'ct'ring-bind#1)#?#*3#1list#0#!#33 ##1list#:)#)#:?#?#:*#*33#==/#1:[#0#:H#!#:^#33 1destr'ct'ring-bind#1)#?#*3#1list#0#1list#!#! 3#33 ##1list#:)#)#:?#?#:*#*33#==/#1:[#0#:H#1!#! 3#:^#33 1destr'ct'ring-bind#1)#1?0#?!3#*3#1list#0#1list#!#! 3#33 ##1list#:)#)#:?0#?0#:?!#?!#:*#*33#==/#1:[#0#:H0#!#:H!#! #:^#33 1destr'ct'ring-bind#1)#1?0#>optional#?!3#*3#1list#0#1list#!#! 3#33 ##1list#:)#)#:?0#?0#:?!#?!#:*#*33#==/#1:[#0#:H0#!#:H!#! #:^#33 1destr'ct'ring-bind#1)#1?0#>optional#?!3#*3#1list#0#1list#!3#33 ##1list#:)#)#:?0#?0#:?!#?!#:*#*33#==/#1:[#0#:H0#!#:H!#89L#:^#33 1destr'ct'ring-bind#1>&e?#)#?#*3#1list#:)#0#:?#!#:*#33 ##1list#:)#)#:?#?#:*#*33#==/#1:[#0#:H#!#:^#33 1destr'ct'ring-bind#1>&e?#)#?#*3#1list#:*#0#:?#!#:)#33 ##1list#:)#)#:?#?#:*#*33#==/#1:[#3#:H#!#:^#03
5ne 9ind o' p#r#*eter you c#n u!e 6ith DESTRUCTURING-BIND #nd #l!o in *#cro p#r#*eter li!t!, though I didn@t *ention it in Ch#pter ,, i! # &56o%' p#r#*eter. I' !peci'ied, it *u!t be the 'ir!t p#r#*eter in # p#r#*eter li!t, #nd it@! bound to the 6hole li!t 'or*.0 %'ter # &56o%' p#r#*eter, other
p#r#*eter! c#n #ppe#r #! u!u#l #nd 6ill e.tr#ct !peci'ic p#rt! o' the li!t <u!t #! they 6ould i' the &56o%' p#r#*eter 6eren@t there. %n e.#*ple o' u!ing &56o%' 6ith DESTRUCTURING-BIND loo9! li9e thi!:
1destr'ct'ring-bind#1>whole#whole#>&e?#)#?#*3#1list#:*#0#:?#!#:)#33 ##1list#:)#)#:?#?#:*#*#:whole#whole33 ==/#1:[#3#:H#!#:^#0#:W:;L-#1:^#0#:H#!#:[#333
4ou@ll u!e # &56o%' p#r#*eter in one o' the *#cro! th#t@! p#rt o' the >&3 gener#tion libr#ry you@ll de?elop in Ch#pter 31. >o6e?er, I h#?e # 'e6 *ore topic! to co?er be'ore you c#n get to th#t. %'ter t6o ch#pter! on the r#ther i!py topic o' con! cell!, you c#n no6 turn to the *ore pro!#ic *#tter o' ho6 to de#l 6ith 'ile! #nd 'ilen#*e!.
1It@! 2It
po!!ible to build # ch#in o' con! cell! 6here the CDR o' the l#!t con! cell i!n@t NIL but !o*e other #to*. &hi! i! c#lled # dotted li!t bec#u!e the l#!t con! i! # dotted p#ir. *#y !ee* th#t the NSUBST '#*ily o' 'unction! c#n #nd in '#ct doe! *odi'y the tree in pl#ce. >o6e?er, there@! one edge c#!e: 6hen the HtreeH p#!!ed i!, in '#ct, #n #to*, it c#n@t be *odi'ied in pl#ce, !o the re!ult o' NSUBST 6ill be # di''erent ob<ect th#n the #rgu*ent: 1ns'bst#C)#C?#C?3# [.
3UNION -It@!
t#9e! only one ele*ent 'ro* e#ch li!t, but i' either li!t cont#in! duplic#te ele*ent!, the re!ult *#y #l!o cont#in duplic#te!. #l!o po!!ible to directly SETF SYMBOL-PLIST. >o6e?er, th#t@! # b#d ide#, #! di''erent code *#y h#?e #dded di''erent propertie! to the !y*bol@! pli!t 'or di''erent re#!on!. I' one piece o' code clobber! the !y*bol@! 6hole pli!t, it *#y bre#9 other code th#t #dded it! o6n propertie! to the pli!t.
53#cro
p#r#*eter li!t! do !upport one p#r#*eter type, &'#7"&o#8'#! p#r#*eter!, 6hich DESTRUCTURING-BIND doe!n@t. >o6e?er, I didn@t di!cu!! th#t p#r#*eter type in Ch#pter ,, #nd you don@t need to 6orry #bout it no6 either.
0When
# &56o%' p#r#*eter i! u!ed in # *#cro p#r#*eter li!t, the 'or* it@! bound to i! the 6hole *#cro 'or*, including the n#*e o' the *#cro.
1open#4/some/(ile/name.t)t43
4ou c#n u!e the ob<ect returned #! the 'ir!t #rgu*ent to #ny o' the re#d 'unction!. /or in!t#nce, to print the 'ir!t line o' the 'ile, you c#n co*bine OPEN, READ-LINE, #nd CLOSE #! 'ollo6!:
1let#11in#1open#4/some/(ile/name.t)t4333 ##1(ormat#t#47a764#1read-line#in33 ##1close#in33
5' cour!e, # nu*ber o' thing! c#n go 6rong 6hile trying to open #nd re#d 'ro* # 'ile. &he 'ile *#y not e.i!t. 5r you *#y une.pectedly hit the end o' the 'ile 6hile re#ding. 7y de'#ult OPEN #nd the .-I<-U# 'unction! 6ill !ign#l #n error in the!e !itu#tion!. In Ch#pter 1), I@ll di!cu!! ho6 to reco?er 'ro* !uch error!. /or no6, ho6e?er, there@! # lighter-6eight !olution: e#ch o' the!e 'unction! #ccept! #rgu*ent! th#t *odi'y it! beh#?ior in the!e e.ception#l !itu#tion!. I' you 6#nt to open # po!!ibly none.i!tent 'ile 6ithout OPEN !ign#ling #n error, you c#n u!e the 9ey6ord #rgu*ent :i(-does-not-e)ist to !peci'y # di''erent beh#?ior. &he three po!!ible ?#lue! #re :error, the de'#ultG :create, 6hich tell! it to go #he#d #nd cre#te the 'ile #nd then proceed #! i' it h#d #lre#dy e.i!tedG #nd NIL, 6hich tell! it to return NIL in!te#d o' # !tre#*. &hu!, you c#n ch#nge the pre?iou! e.#*ple to de#l 6ith the po!!ibility th#t the 'ile *#y not e.i!t.
1let#11in#1open#4/some/(ile/name.t)t4#:i(-does-not-e)ist#nil333 ##1when#in ####1(ormat#t#47a764#1read-line#in33 ####1close#in333
&he re#ding 'unction!--READ-CHAR, READ-LINE, #nd READ--#ll t#9e #n option#l #rgu*ent, 6hich de'#ult! to true, th#t !peci'ie! 6hether they !hould !ign#l #n error i' they@re c#lled #t the end o' the 'ile. I' th#t #rgu*ent i! NIL, they in!te#d return the ?#lue o' their third #rgu*ent, 6hich de'#ult! to NIL. &hu!, you could print #ll the line! in # 'ile li9e thi!:
1let#11in#1open#4/some/(ile/name.t)t4#:i(-does-not-e)ist#nil333 ##1when#in ####1loop#(or#line#=#1read-line#in#nil3 #########while#line#do#1(ormat#t#47a764#line33 ####1close#in333
5' the three te.t-re#ding 'unction!, READ i! uniFue to i!p. &hi! i! the !#*e 'unction th#t pro?ide! the * in the $(P #nd th#t@! u!ed to re#d i!p !ource code. (#ch ti*e it@! c#lled, it re#d! # !ingle !e.pre!!ion, !9ipping 6hite!p#ce #nd co**ent!, #nd return! the i!p ob<ect denoted by the !e.pre!!ion. /or in!t#nce, !uppo!e /some/(ile/name.t)t h#! the 'ollo6ing content!:
10#!#33 4"6 4a#string4#S#this#is#a#comment 11a#b3 #1c#d33
In other 6ord!, it cont#in! 'our !-e.pre!!ion!: # li!t o' nu*ber!, # nu*ber, # !tring, #nd # li!t o' li!t!. 4ou c#n re#d tho!e e.pre!!ion! li9e thi!:
$L-+,-./#1de(parameter#UsU#1open#4/some/(ile/name.t)t433 U,U $L-+,-./#1read#UsU3 10#!#33
%! you !#6 in Ch#pter 3, you c#n u!e PRINT to print i!p ob<ect! in Hre#d#bleH 'or*. &hu!, 6hene?er you need to !tore # bit o' d#t# in # 'ile, PRINT #nd READ pro?ide #n e#!y 6#y to do it 6ithout h#?ing to de!ign # d#t# 'or*#t or 6rite # p#r!er. &hey e?en--#! the pre?iou! e.#*ple de*on!tr#ted--gi?e you co**ent! 'or 'ree. %nd bec#u!e !-e.pre!!ion! 6ere de!igned to be hu*#n edit#ble, it@! #l!o # 'ine 'or*#t 'or thing! li9e con'igur#tion 'ile!.1
Bu%k Reads
5ne l#!t re#ding 'unction, READ-SEQUENCE, 6or9! 6ith both ch#r#cter #nd bin#ry !tre#*!. 4ou p#!! it # !eFuence Btypic#lly # ?ectorC #nd # !tre#*, #nd it #tte*pt! to 'ill the !eFuence 6ith d#t# 'ro* the !tre#*. It return! the inde. o' the 'ir!t ele*ent o' the !eFuence th#t 6#!n@t 'illed or the length o' the !eFuence i' it 6#! #ble to co*pletely 'ill it. 4ou c#n #l!o p#!! :start #nd :end 9ey6ord #rgu*ent! to !peci'y # !ub!eFuence th#t !hould be 'illed in!te#d. &he !eFuence #rgu*ent *u!t be # type th#t c#n hold ele*ent! o' the !tre#*@! ele*ent type. Since *o!t oper#ting !y!te*! !upport !o*e 'or* o' bloc9 I;5, READ-SEQUENCE i! li9ely to be Fuite # bit *ore e''icient th#n 'illing # !eFuence by repe#tedly c#lling READ-BYTE or READ-CHAR.
Fi%e 7utput
&o 6rite d#t# to # 'ile, you need #n output !tre#*, 6hich you obt#in by c#lling OPEN 6ith # :direction 9ey6ord #rgu*ent o' :o'tp't. When opening # 'ile 'or output, OPEN #!!u*e! the 'ile !houldn@t #lre#dy e.i!t #nd 6ill !ign#l #n error i' it doe!. >o6e?er, you c#n ch#nge th#t beh#?ior 6ith the :i(-e)ists 9ey6ord #rgu*ent. P#!!ing the ?#lue :s'persede tell! OPEN to repl#ce the e.i!ting 'ile. P#!!ing :append c#u!e! OPEN to open the e.i!ting 'ile !uch th#t ne6 d#t# 6ill be 6ritten #t the end o' the 'ile, 6hile :overwrite return! # !tre#* th#t 6ill o?er6rite e.i!ting d#t# !t#rting 'ro* the beginning o' the 'ile. %nd p#!!ing NIL 6ill c#u!e OPEN to return NIL in!te#d o' # !tre#* i' the 'ile #lre#dy e.i!t!. % typic#l u!e o' OPEN 'or output loo9! li9e thi!:
1open#4/some/(ile/name.t)t4#:direction#:o'tp't#:i(-e)ists#:s'persede3
Co**on i!p #l!o pro?ide! !e?er#l 'unction! 'or 6riting d#t#: WRITE-CHAR 6rite! # !ingle ch#r#cter to the !tre#*. WRITE-LINE 6rite! # !tring 'ollo6ed by # ne6line, 6hich 6ill be output #! the #ppropri#te end-o'-line ch#r#cter or ch#r#cter! 'or the pl#t'or*. %nother 'unction, WRITE-STRING, 6rite! # !tring 6ithout #dding #ny end-o'-line ch#r#cter!. &6o di''erent 'unction! c#n print <u!t # ne6line: TERPRI--!hort 'or Hter*in#te printH--uncondition#lly print! # ne6line ch#r#cter, #nd FRESH-LINE print! # ne6line ch#r#cter unle!! the !tre#* i! #t the beginning o' # line. FRESH-LINE i! h#ndy 6hen you 6#nt to #?oid !puriou! bl#n9 line! in te.tu#l output gener#ted by di''erent 'unction! c#lled in !eFuence. /or e.#*ple, !uppo!e you h#?e one 'unction th#t gener#te! output th#t !hould #l6#y! be 'ollo6ed by # line bre#9 #nd #nother th#t !hould !t#rt on # ne6 line. 7ut #!!u*e th#t i' the 'unction! #re c#lled one #'ter the other, you don@t 6#nt # bl#n9 line bet6een the t6o bit! o' output. I' you u!e FRESH-LINE #t the beginning o' the !econd 'unction, it! output 6ill #l6#y! !t#rt on # ne6 line, but i' it@! c#lled right #'ter the 'ir!t, it 6on@t e*it #n e.tr# line bre#9. Se?er#l 'unction! output i!p d#t# #! !-e.pre!!ion!: PRINT print! #n !-e.pre!!ion preceded by #n endo'-line #nd 'ollo6ed by # !p#ce. PRIN1 print! <u!t the !-e.pre!!ion. %nd the 'unction PPRINT print! !-e.pre!!ion! li9e PRINT #nd PRIN1 but u!ing the Hpretty printer,H 6hich trie! to print it! output in #n #e!thetic#lly ple#!ing 6#y. >o6e?er, not #ll ob<ect! c#n be printed in # 'or* th#t READ 6ill under!t#nd. &he ?#ri#ble *PRINTREADABLY* control! 6h#t h#ppen! i' you try to print !uch #n ob<ect 6ith PRINT, PRIN1, or PPRINT. When it@! NIL, the!e 'unction! 6ill print the ob<ect in # !peci#l !ynt#. th#t@! gu#r#nteed to c#u!e READ to !ign#l #n error i' it trie! to re#d itG other6i!e they 6ill !ign#l #n error r#ther th#n print the ob<ect. %nother 'unction, PRINC, #l!o print! i!p ob<ect!, but in # 6#y de!igned 'or hu*#n con!u*ption. /or in!t#nce, PRINC print! !tring! 6ithout Fuot#tion *#r9!. 4ou c#n gener#te *ore el#bor#te te.t output 6ith the incredibly 'le.ible i' !o*e6h#t #rc#ne FORMAT 'unction. I@ll di!cu!! !o*e o' the *ore i*port#nt det#il! o' FORMAT, 6hich e!!enti#lly de'ine! # *ini-l#ngu#ge 'or e*itting 'or*#tted output, in Ch#pter 1,. &o 6rite bin#ry d#t# to # 'ile, you h#?e to OPEN the 'ile 6ith the !#*e :element-t?pe #rgu*ent #! you did to re#d it: C1'nsigned-b?te#R3. 4ou c#n then 6rite indi?idu#l byte! to the !tre#* 6ith WRITE-BYTE. &he bul9 output 'unction WRITE-SEQUENCE #ccept! both bin#ry #nd ch#r#cter !tre#*! #! long #! #ll the ele*ent! o' the !eFuence #re o' #n #ppropri#te type 'or the !tre#*, either ch#r#cter! or byte!. %! 6ith READ-SEQUENCE, thi! 'unction i! li9ely to be Fuite # bit *ore e''icient th#n 6riting the ele*ent! o' the !eFuence one #t # ti*e.
#%osing Fi%es
%! #nyone 6ho h#! 6ritten code th#t de#l! 6ith lot! o' 'ile! 9no6!, it@! i*port#nt to clo!e 'ile! 6hen you@re done 6ith the*, bec#u!e 'ile h#ndle! tend to be # !c#rce re!ource. I' you open 'ile! #nd don@t clo!e the*, you@ll !oon di!co?er you c#n@t open #ny *ore 'ile!.5 It *ight !ee* !tr#ight'or6#rd enough to <u!t be !ure e?ery OPEN h#! # *#tching CLOSE. /or in!t#nce, you could #l6#y! !tructure your 'ile u!ing code li9e thi!:
1let#11stream#1open#4/some/(ile/name.t)t4333 ##SS#do#st'((#with#stream ##1close#stream33
>o6e?er, thi! #ppro#ch !u''er! 'ro* t6o proble*!. 5ne i! !i*ply th#t it@! error prone--i' you 'orget the
CLOSE, the code 6ill le#9 # 'ile h#ndle e?ery ti*e it run!. &he other--#nd *ore !igni'ic#nt--proble* i! th#t there@! no gu#r#ntee you@ll get to the CLOSE. /or in!t#nce, i' the code prior to the CLOSE cont#in! # RETURN or RETURN-FROM, you could le#?e the LET 6ithout clo!ing the !tre#*. 5r, #! you@ll !ee in Ch#pter 1), i' #ny o' the code be'ore the CLOSE !ign#l! #n error, control *#y <u*p out o' the LET to #n error h#ndler #nd ne?er co*e b#c9 to clo!e the !tre#*. Co**on i!p pro?ide! # gener#l !olution to the proble* o' ho6 to en!ure th#t cert#in code #l6#y! run!: the !peci#l oper#tor UNWIND-PROTECT, 6hich I@ll di!cu!! in Ch#pter 20. >o6e?er, bec#u!e the p#ttern o' opening # 'ile, doing !o*ething 6ith the re!ulting !tre#*, #nd then clo!ing the !tre#* i! !o co**on, Co**on i!p pro?ide! # *#cro, WITH-OPEN-FILE, built on top o' UNWIND-PROTECT, to enc#p!ul#te thi! p#ttern. &hi! i! the b#!ic 'or*:
1with-open-(ile#1stream-var#open-argument*3 ##body-form*3
&he 'or*! in bod0)forms #re e?#lu#ted 6ith stream)var bound to # 'ile !tre#* opened by # c#ll to OPEN 6ith open)arguments #! it! #rgu*ent!. WITH-OPEN-FILE then en!ure! the !tre#* in stream) var i! clo!ed be'ore the WITH-OPEN-FILE 'or* return!. &hu!, you c#n 6rite thi! to re#d # line 'ro* # 'ile:
1with-open-(ile#1stream#4/some/(ile/name.t)t43 ##1(ormat#t#47a764#1read-line#stream333
&o cre#te # ne6 'ile, you c#n 6rite !o*ething li9e thi!:
1with-open-(ile#1stream#4/some/(ile/name.t)t4#:direction#:o'tp't3 ##1(ormat#stream#4,ome#te)t.433
4ou@ll prob#bly u!e WITH-OPEN-FILE 'or )0-)) percent o' the 'ile I;5 you do--the only ti*e you need to u!e r#6 OPEN #nd CLOSE c#ll! i! i' you need to open # 'ile in # 'unction #nd 9eep the !tre#* #round #'ter the 'unction return!. In th#t c#!e, you *u!t t#9e c#re to e?entu#lly clo!e the !tre#* your!el', or you@ll le#9 'ile de!criptor! #nd *#y e?entu#lly end up un#ble to open #ny *ore 'ile!.
Fi%ena$es
So '#r you@?e u!ed !tring! to repre!ent 'ilen#*e!. >o6e?er, u!ing !tring! #! 'ilen#*e! tie! your code to # p#rticul#r oper#ting !y!te* #nd 'ile !y!te*. i9e6i!e, i' you progr#**#tic#lly con!truct n#*e! #ccording to the rule! o' # p#rticul#r n#*ing !che*e B!ep#r#ting directorie! 6ith ;, !#yC, you #l!o tie your code to # p#rticul#r 'ile !y!te*. &o #?oid thi! 9ind o' nonport#bility, Co**on i!p pro?ide! #nother repre!ent#tion o' 'ilen#*e!: p#thn#*e ob<ect!. P#thn#*e! repre!ent 'ilen#*e! in # !tructured 6#y th#t *#9e! the* e#!y to *#nipul#te 6ithout tying the* to # p#rticul#r 'ilen#*e !ynt#.. %nd the burden o' tr#n!l#ting b#c9 #nd 'orth bet6een !tring! in the loc#l !ynt#.--c#lled namestrings--#nd p#thn#*e! i! pl#ced on the i!p i*ple*ent#tion. 8n'ortun#tely, #! 6ith *#ny #b!tr#ction! de!igned to hide the det#il! o' 'und#*ent#lly di''erent underlying !y!te*!, the p#thn#*e #b!tr#ction introduce! it! o6n co*plic#tion!. When p#thn#*e! 6ere de!igned, the !et o' 'ile !y!te*! in gener#l u!e 6#! Fuite # bit *ore ?#rieg#ted th#n tho!e in co**on u!e tod#y. Con!eFuently, !o*e noo9! #nd cr#nnie! o' the p#thn#*e #b!tr#ction *#9e little !en!e i' #ll you@re concerned #bout i! repre!enting 8ni. or Windo6! 'ilen#*e!. >o6e?er, once you under!t#nd 6hich p#rt! o' the p#thn#*e #b!tr#ction you c#n ignore #! #rti'#ct! o' p#thn#*e!@ e?olution#ry hi!tory,
they do pro?ide # con?enient 6#y to *#nipul#te 'ilen#*e!.0 3o!t pl#ce! # 'ilen#*e i! c#lled 'or, you c#n u!e either # n#*e!tring or # p#thn#*e. Which to u!e depend! *o!tly on 6here the n#*e origin#ted. /ilen#*e! pro?ided by the u!er--'or e.#*ple, #! #rgu*ent! or #! ?#lue! in con'igur#tion 'ile!--6ill typic#lly be n#*e!tring!, !ince the u!er 9no6! 6h#t oper#ting !y!te* they@re running on #nd !houldn@t be e.pected to c#re #bout the det#il! o' ho6 i!p repre!ent! 'ilen#*e!. 7ut progr#**#tic#lly gener#ted 'ilen#*e! 6ill be p#thn#*e! bec#u!e you c#n cre#te the* port#bly. % !tre#* returned by OPEN #l!o repre!ent! # 'ilen#*e, n#*ely, the 'ilen#*e th#t 6#! origin#lly u!ed to open the !tre#*. &ogether the!e three type! #re collecti?ely re'erred to #! pathname designators. %ll the built-in 'unction! th#t e.pect # 'ilen#*e #rgu*ent #ccept #ll three type! o' p#thn#*e de!ign#tor. /or in!t#nce, #ll the pl#ce! in the pre?iou! !ection 6here you u!ed # !tring to repre!ent # 'ilen#*e, you could #l!o h#?e p#!!ed # p#thn#*e ob<ect or # !tre#*. >o6 We =ot >ere &he hi!toric#l di?er!ity o' 'ile !y!te*! in e.i!tence during the 20! #nd ,0! c#n be e#!y to 'orget. Lent Pit*#n, one o' the princip#l technic#l editor! o' the Co**on i!p !t#nd#rd, de!cribed the !itu#tion once in co*p.l#ng.li!p B3e!!#ge-I+: s(w*oQ4np6w.(s(Pworld.std.comC thu!ly: &he do*in#nt 'ile !y!te*! #t the ti*e the de!ign Jo' Co**on i!pK 6#! done 6ere &5PS10, &(:(N, &5PS-20, 1%N 13S, %&]& 8ni., 3I& 3ultic!, 3I& I&S, not to *ention # bunch o' *#in'r#*e J5S!K. So*e 6ere upperc#!e only, !o*e *i.ed, !o*e 6ere c#!e!en!iti?e but c#!e- tr#n!l#ting Bli9e C C. So*e h#d dir! #! 'ile!, !o*e not. So*e h#d Fuote ch#r! 'or 'unny 'ile ch#r!, !o*e not. So*e h#d 6ildc#rd!, !o*e didn@t. So*e h#d :up in rel#ti?e p#thn#*e!, !o*e didn@t. So*e h#d n#*#ble root dir!, !o*e didn@t. &here 6ere 'ile !y!te*! 6ith no directorie!, 'ile !y!te*! 6ith non-hier#rchic#l directorie!, 'ile !y!te*! 6ith no 'ile type!, 'ile !y!te*! 6ith no ?er!ion!, 'ile !y!te*! 6ith no de?ice!, #nd !o on. I' you loo9 #t the p#thn#*e #b!tr#ction 'ro* the point o' ?ie6 o' #ny !ingle 'ile !y!te*, it !ee*! b#roFue. >o6e?er, i' you t#9e e?en t6o !uch !i*il#r 'ile !y!te*! #! Windo6! #nd 8ni., you c#n #lre#dy begin to !ee di''erence! the p#thn#*e !y!te* c#n help #b!tr#ct #6#y--Windo6! 'ilen#*e! cont#in # dri?e letter, 'or in!t#nce, 6hile 8ni. 'ilen#*e! don@t. &he other #d?#nt#ge o' h#?ing the p#thn#*e #b!tr#ction de!igned to h#ndle the 6ide ?#riety o' 'ile !y!te*! th#t e.i!ted in the p#!t i! th#t it@! *ore li9ely to be #ble to h#ndle 'ile !y!te*! th#t *#y e.i!t in the 'uture. I', !#y, ?er!ioning 'ile !y!te*! co*e b#c9 into ?ogue, Co**on i!p 6ill be re#dy.
p#thn#*e, it@! !i*ply returned. When it@! # !tre#*, the origin#l 'ilen#*e i! e.tr#cted #nd returned. When the de!ign#tor i! # n#*e!tring, ho6e?er, it@! p#r!ed #ccording to the loc#l 'ilen#*e !ynt#.. &he l#ngu#ge !t#nd#rd, #! # pl#t'or*-neutr#l docu*ent, doe!n@t !peci'y #ny p#rticul#r *#pping 'ro* n#*e!tring to p#thn#*e, but *o!t i*ple*ent#tion! 'ollo6 the !#*e con?ention! on # gi?en oper#ting !y!te*. 5n 8ni. 'ile !y!te*!, only the directory, n#*e, #nd type co*ponent! #re typic#lly u!ed. 5n Windo6!, one *ore co*ponent--u!u#lly the de?ice or ho!t--hold! the dri?e letter. 5n the!e pl#t'or*!, # n#*e!tring i! p#r!ed by 'ir!t !plitting it into ele*ent! on the p#th !ep#r#tor--# !l#!h on 8ni. #nd # !l#!h or b#c9!l#!h on Windo6!. &he dri?e letter on Windo6! 6ill be pl#ced into either the de?ice or the ho!t co*ponent. %ll but the l#!t o' the other n#*e ele*ent! #re pl#ced in # li!t !t#rting 6ith :absol'te or :relative depending on 6hether the n#*e Bignoring the dri?e letter, i' #nyC beg#n 6ith # p#th !ep#r#tor. &hi! li!t beco*e! the directory co*ponent o' the p#thn#*e. &he l#!t ele*ent i! then !plit on the right*o!t dot, i' #ny, #nd the t6o p#rt! put into the n#*e #nd type co*ponent! o' the p#thn#*e.2 4ou c#n e.#*ine the!e indi?idu#l co*ponent! o' # p#thn#*e 6ith the 'unction! PATHNAMEDIRECTORY, PATHNAME-NAME, #nd PATHNAME-TYPE.
1pathname-director?#1pathname#4/(oo/bar/ba*.t)t433#==/#1:IL,;L+F-#4(oo4#4bar43 1pathname-name#1pathname#4/(oo/bar/ba*.t)t433######==/#4ba*4 1pathname-t?pe#1pathname#4/(oo/bar/ba*.t)t433######==/#4t)t4
&hree other 'unction!--PATHNAME-HOST, PATHNAME-DEVICE, #nd PATHNAME-VERSION--#llo6 you to get #t the other three p#thn#*e co*ponent!, though they@re unli9ely to h#?e intere!ting ?#lue! on 8ni.. 5n Windo6! either PATHNAME-HOST or PATHNAME-DEVICE 6ill return the dri?e letter. i9e *#ny other built-in ob<ect!, p#thn#*e! h#?e their o6n re#d !ynt#., Np 'ollo6ed by # doubleFuoted !tring. &hi! #llo6! you to print #nd re#d b#c9 !-e.pre!!ion! cont#ining p#thn#*e ob<ect!, but bec#u!e the !ynt#. depend! on the n#*e!tring p#r!ing #lgorith*, !uch d#t# i!n@t nece!!#rily port#ble bet6een oper#ting !y!te*!.
1pathname#4/(oo/bar/ba*.t)t43#==/#Np4/(oo/bar/ba*.t)t4
&o tr#n!l#te # p#thn#*e b#c9 to # n#*e!tring--'or in!t#nce, to pre!ent to the u!er--you c#n u!e the 'unction NAMESTRING, 6hich t#9e! # p#thn#*e de!ign#tor #nd return! # n#*e!tring. &6o other 'unction!, DIRECTORY-NAMESTRING #nd FILE-NAMESTRING, return # p#rti#l n#*e!tring. DIRECTORY-NAMESTRING co*bine! the ele*ent! o' the directory co*ponent into # loc#l directory n#*e, #nd FILE-NAMESTRING co*bine! the n#*e #nd type co*ponent!.,
1namestring#Np4/(oo/bar/ba*.t)t43###########==/#4/(oo/bar/ba*.t)t4 1director?-namestring#Np4/(oo/bar/ba*.t)t43#==/#4/(oo/bar/4 1(ile-namestring#Np4/(oo/bar/ba*.t)t43######==/#4ba*.t)t4
>o6e?er, i' you 6#nt your progr#*! to be port#ble, you prob#bly don@t 6#nt to *#9e p#thn#*e! co*pletely 'ro* !cr#tch: e?en though the p#thn#*e #b!tr#ction protect! you 'ro* unport#ble 'ilen#*e !ynt#., 'ilen#*e! c#n be unport#ble in other 6#y!. /or in!t#nce, the 'ilen#*e /home/peter/(oo.t)t i! no good on #n 5S N bo. 6here /home/ i! c#lled /+sers/. %nother re#!on not to *#9e p#thn#*e! co*pletely 'ro* !cr#tch i! th#t di''erent i*ple*ent#tion! u!e the p#thn#*e co*ponent! !lightly di''erently. /or in!t#nce, #! *entioned pre?iou!ly, !o*e Windo6!b#!ed i!p i*ple*ent#tion! !tore the dri?e letter in the de?ice co*ponent 6hile other! !tore it in the ho!t co*ponent. I' you 6rite code li9e thi!:
1ma&e-pathname#:device#4c4#:director?#C1:absol'te#4(oo4#4bar43#:name#4ba*43
it 6ill be correct on !o*e i*ple*ent#tion! but not on other!. $#ther th#n *#9ing n#*e! 'ro* !cr#tch, you c#n build # ne6 p#thn#*e b#!ed on #n e.i!ting p#thn#*e 6ith MA+E-PATHNAME@! 9ey6ord p#r#*eter :de(a'lts. With thi! p#r#*eter you c#n pro?ide # p#thn#*e de!ign#tor, 6hich 6ill !upply the ?#lue! 'or #ny co*ponent! not !peci'ied by other #rgu*ent!. /or e.#*ple, the 'ollo6ing e.pre!!ion cre#te! # p#thn#*e 6ith #n .html e.ten!ion #nd #ll other co*ponent! the !#*e #! the p#thn#*e in the ?#ri#ble inp't-(ile:
1ma&e-pathname#:t?pe#4html4#:de(a'lts#inp't-(ile3
%!!u*ing the ?#lue in inp't-(ile 6#! # u!er-pro?ided n#*e, thi! code 6ill be robu!t in the '#ce o' oper#ting !y!te* #nd i*ple*ent#tion di''erence! !uch #! 6hether 'ilen#*e! h#?e dri?e letter! in the* #nd 6here they@re !tored in # p#thn#*e i' they do.10 4ou c#n u!e the !#*e techniFue to cre#te # p#thn#*e 6ith # di''erent directory co*ponent.
1ma&e-pathname#:director?#C1:relative#4bac&'ps43#:de(a'lts#inp't-(ile3
>o6e?er, thi! 6ill cre#te # p#thn#*e 6ho!e 6hole directory co*ponent i! the rel#ti?e directory bac&'ps/, reg#rdle!! o' #ny directory co*ponent inp't-(ile *#y h#?e h#d. /or e.#*ple:
1ma&e-pathname#:director?#C1:relative#4bac&'ps43 ###############:de(a'lts#Np4/(oo/bar/ba*.t)t43#==/#Np4bac&'ps/ba*.t)t4
So*eti*e!, though, you 6#nt to co*bine t6o p#thn#*e!, #t le#!t one o' 6hich h#! # rel#ti?e directory co*ponent, by co*bining their directory co*ponent!. /or in!t#nce, !uppo!e you h#?e # rel#ti?e p#thn#*e !uch #! Np4(oo/bar.html4 th#t you 6#nt to co*bine 6ith #n #b!olute p#thn#*e !uch #! Np4/www/html/4 to get Np4/www/html/(oo/bar.html4. In th#t c#!e, MA+E-PATHNAME 6on@t doG in!te#d, you 6#nt MERGE-PATHNAMES. MERGE-PATHNAMES t#9e! t6o p#thn#*e! #nd *erge! the*, 'illing in #ny NIL co*ponent! in the 'ir!t p#thn#*e 6ith the corre!ponding ?#lue 'ro* the !econd p#thn#*e, *uch li9e MA+E-PATHNAME 'ill! in #ny un!peci'ied co*ponent! 6ith co*ponent! 'ro* the :de(a'lts #rgu*ent. >o6e?er, MERGE-PATHNAMES tre#t! the directory co*ponent !peci#lly: i' the 'ir!t p#thn#*e@! directory i! rel#ti?e, the directory co*ponent o' the re!ulting p#thn#*e 6ill be the 'ir!t p#thn#*e@! directory rel#ti?e to the !econd p#thn#*e@! directory. &hu!:
1merge-pathnames#Np4(oo/bar.html4#Np4/www/html/43#==/#Np4/www/html/(oo/bar.html4
&he !econd p#thn#*e c#n #l!o be rel#ti?e, in 6hich c#!e the re!ulting p#thn#*e 6ill #l!o be rel#ti?e.
1merge-pathnames#Np4(oo/bar.html4#Np4html/43#==/#Np4html/(oo/bar.html4
&o re?er!e thi! proce!! #nd obt#in # 'ilen#*e rel#ti?e to # p#rticul#r root directory, you c#n u!e the h#ndy 'unction ENOUGH-NAMESTRING.
1eno'gh-namestring#Np4/www/html/(oo/bar.html4#Np4/www/43#==/#4html/(oo/bar.html4
4ou c#n then co*bine ENOUGH-NAMESTRING 6ith MERGE-PATHNAMES to cre#te # p#thn#*e repre!enting the !#*e n#*e but in # di''erent root.
1merge-pathnames ##1eno'gh-namestring#Np4/www/html/(oo/bar/ba*.html4#Np4/www/43 ##Np4/www-bac&'ps/43#==/#Np4/www-bac&'ps/html/(oo/bar/ba*.html4
MERGE-PATHNAMES i! #l!o u!ed intern#lly by the !t#nd#rd 'unction! th#t #ctu#lly #cce!! 'ile! in the 'ile !y!te* to 'ill in inco*plete p#thn#*e!. /or in!t#nce, !uppo!e you *#9e # p#thn#*e 6ith <u!t # n#*e #nd # type.
1ma&e-pathname#:name#4(oo4#:t?pe#4t)t43#==/#Np4(oo.t)t4
I' you try to u!e thi! p#thn#*e #! #n #rgu*ent to OPEN, the *i!!ing co*ponent!, !uch #! the directory, *u!t be 'illed in be'ore i!p 6ill be #ble to tr#n!l#te the p#thn#*e to #n #ctu#l 'ilen#*e. Co**on i!p 6ill obt#in ?#lue! 'or the *i!!ing co*ponent! by *erging the gi?en p#thn#*e 6ith the ?#lue o' the ?#ri#ble *DEFAULT-PATHNAME-DEFAULTS*. &he initi#l ?#lue o' thi! ?#ri#ble i! deter*ined by the i*ple*ent#tion but i! u!u#lly # p#thn#*e 6ith # directory co*ponent repre!enting the directory 6here i!p 6#! !t#rted #nd #ppropri#te ?#lue! 'or the ho!t #nd de?ice co*ponent!, i' needed. I' in?o9ed 6ith <u!t one #rgu*ent, MERGE-PATHNAMES 6ill *erge the #rgu*ent 6ith the ?#lue o' *DEFAULTPATHNAME-DEFAULTS*. /or in!t#nce, i' *DEFAULT-PATHNAME-DEFAULTS* i! Np4/home/peter/4, then you@d get the 'ollo6ing:
1merge-pathnames#Np4(oo.t)t43#==/#Np4/home/peter/(oo.t)t4
When you cre#te p#thn#*e! 6ith MA+E-PATHNAME, you c#n control 6hich 'or* you get, but you need to be c#re'ul 6hen de#ling 6ith n#*e!tring!. %ll current i*ple*ent#tion! cre#te 'ile 'or* p#thn#*e! unle!! the n#*e!tring end! 6ith # p#th !ep#r#tor. 7ut you c#n@t rely on u!er-!upplied n#*e!tring! nece!!#rily being in one 'or* or #nother. /or in!t#nce, !uppo!e you@?e pro*pted the u!er 'or # directory to !#?e # 'ile in #nd they entered 4/home/peter4. I' you p#!! th#t ?#lue #! the :de(a'lts #rgu*ent o' MA+E-PATHNAME li9e thi!:
1ma&e-pathname#:name#4(oo4#:t?pe#4t)t4#:de(a'lts#'ser-s'pplied-name3
you@ll end up !#?ing the 'ile in /home/(oo.t)t r#ther th#n the intended /home/peter/(oo.t)t bec#u!e the 4peter4 in the n#*e!tring 6ill be pl#ced in the n#*e co*ponent 6hen 'ser-s'pplied-name i! con?erted to # p#thn#*e. In the p#thn#*e port#bility libr#ry I@ll di!cu!! in the ne.t ch#pter, you@ll 6rite # 'unction c#lled pathname-as-director? th#t con?ert! # p#thn#*e to directory 'or*. With th#t 'unction you c#n reli#bly !#?e the 'ile in the directory indic#ted by the u!er.
1ma&e-pathname ##:name#4(oo4#:t?pe#4t)t4#:de(a'lts#1pathname-as-director?#'ser-s'pplied-name33
:ote th#t i' you p#!! ENSURE-DIRECTORIES-EXIST # directory n#*e, it !hould be in directory 'or*, or the le#' directory 6on@t be cre#ted. &he 'unction! FILE-WRITE-DATE #nd FILE-AUTHOR both t#9e # p#thn#*e de!ign#tor. FILEWRITE-DATE return! the ti*e in nu*ber o' !econd! !ince *idnight D#nu#ry 1, 1)00, =reen6ich *e#n ti*e B=3&C, th#t the 'ile 6#! l#!t 6ritten, #nd FILE-AUTHOR return!, on 8ni. #nd Windo6!, the 'ile o6ner.12 &o 'ind the length o' # 'ile, you c#n u!e the 'unction FILE-LENGTH. /or hi!toric#l re#!on! FILELENGTH t#9e! # !tre#* #! #n #rgu*ent r#ther th#n # p#thn#*e. In theory thi! #llo6! FILE-LENGTH to return the length in ter*! o' the ele*ent type o' the !tre#*. >o6e?er, !ince on *o!t pre!ent-d#y oper#ting !y!te*!, the only in'or*#tion #?#il#ble #bout the length o' # 'ile, !hort o' #ctu#lly re#ding the 6hole 'ile to *e#!ure it, i! it! length in byte!, th#t@! 6h#t *o!t i*ple*ent#tion! return, e?en 6hen FILE-LENGTH i! p#!!ed # ch#r#cter !tre#*. >o6e?er, the !t#nd#rd doe!n@t reFuire thi! beh#?ior, !o 'or predict#ble re!ult!, the be!t 6#y to get the length o' # 'ile i! to u!e # bin#ry !tre#*.13
1with-open-(ile#1in#(ilename#:element-t?pe#C1'nsigned-b?te#R33 ##1(ile-length#in33
% rel#ted 'unction th#t #l!o t#9e! #n open 'ile !tre#* #! it! #rgu*ent i! FILE-POSITION. When c#lled 6ith <u!t # !tre#*, thi! 'unction return! the current po!ition in the 'ile--the nu*ber o' ele*ent! th#t h#?e been re#d 'ro* or 6ritten to the !tre#*. When c#lled 6ith t6o #rgu*ent!, the !tre#* #nd # po!ition de!ign#tor, it !et! the po!ition o' the !tre#* to the de!ign#ted po!ition. &he po!ition de!ign#tor *u!t be the 9ey6ord :start, the 9ey6ord :end, or # non-neg#ti?e integer. &he t6o 9ey6ord! !et the po!ition o' the !tre#* to the !t#rt or end o' the 'ile 6hile #n integer *o?e! to the indic#ted po!ition in the 'ile. With # bin#ry !tre#* the po!ition i! !i*ply # byte o''!et into the 'ile. >o6e?er, 'or ch#r#cter !tre#*! thing! #re # bit *ore co*plic#ted bec#u!e o' ch#r#cter-encoding i!!ue!. 4our be!t bet, i' you need to <u*p #round 6ithin # 'ile o' te.tu#l d#t#, i! to only e?er p#!!, #! # !econd #rgu*ent to the t6o#rgu*ent ?er!ion o' FILE-POSITION, # ?#lue pre?iou!ly returned by the one-#rgu*ent ?er!ion o' FILE-POSITION 6ith the !#*e !tre#* #rgu*ent.
Si*il#rly, MA+E-STRING-OUTPUT-STREAM cre#te! # !tre#* you c#n u!e 6ith FORMAT, PRINT, WRITE-CHAR, WRITE-LINE, #nd !o on. It t#9e! no #rgu*ent!. Wh#te?er you 6rite, # !tring output !tre#* 6ill be #ccu*ul#ted into # !tring th#t c#n then be obt#ined 6ith the 'unction GET-OUTPUT-
STREAM-STRING. (#ch ti*e you c#ll GET-OUTPUT-STREAM-STRING, the !tre#*@! intern#l !tring i! cle#red !o you c#n reu!e #n e.i!ting !tring output !tre#*. >o6e?er, you@ll r#rely u!e the!e 'unction! directly, bec#u!e the *#cro! WITH-INPUT-FROMSTRING #nd WITH-OUTPUT-TO-STRING pro?ide # *ore con?enient inter'#ce. WITH-INPUTFROM-STRING i! !i*il#r to WITH-OPEN-FILE--it cre#te! # !tring input !tre#* 'ro* # gi?en !tring #nd then e.ecute! the 'or*! in it! body 6ith the !tre#* bound to the ?#ri#ble you pro?ide. /or in!t#nce, in!te#d o' the LET 'or* 6ith the e.plicit UNWIND-PROTECT, you@d prob#bly 6rite thi!:
1with-inp't-(rom-string#1s#40.!343 ##1read#s33
&he WITH-OUTPUT-TO-STRING *#cro i! !i*il#r: it bind! # ne6ly cre#ted !tring output !tre#* to # ?#ri#ble you n#*e #nd then e.ecute! it! body. %'ter #ll the body 'or*! h#?e been e.ecuted, WITHOUTPUT-TO-STRING return! the ?#lue th#t 6ould be returned by GET-OUTPUT-STREAMSTRING.
$L-+,-./#1with-o'tp't-to-string#1o't3 ############1(ormat#o't#4hello5#world#43 ############1(ormat#o't#47s4#1list#0#!#3333 4hello5#world#10#!#334
&he other 9ind! o' !tre#*! de'ined in the l#ngu#ge !t#nd#rd pro?ide ?#riou! 9ind! o' !tre#* Hplu*bing,H #llo6ing you to plug together !tre#*! in #l*o!t #ny con'igur#tion. % BROADCASTSTREAM i! #n output !tre#* th#t !end! #ny d#t# 6ritten to it to # !et o' output !tre#*! pro?ided #! #rgu*ent! to it! con!tructor 'unction, MA+E-BROADCAST-STREAM.1- Con?er!ely, # CONCATENATED-STREAM i! #n input !tre#* th#t t#9e! it! input 'ro* # !et o' input !tre#*!, *o?ing 'ro* !tre#* to !tre#* #! it hit! the end o' e#ch !tre#*. CONCATENATED-STREAM! #re con!tructed 6ith the 'unction MA+E-CONCATENATED-STREAM, 6hich t#9e! #ny nu*ber o' input !tre#*! #! #rgu*ent!. &6o 9ind! o' bidirection#l !tre#*! th#t c#n plug together !tre#*! in # couple 6#y! #re TWO-WAYSTREAM #nd ECHO-STREAM. &heir con!tructor 'unction!, MA+E-TWO-WAY-STREAM #nd MA+EECHO-STREAM, both t#9e t6o #rgu*ent!, #n input !tre#* #nd #n output !tre#*, #nd return # !tre#* o' the #ppropri#te type, 6hich you c#n u!e 6ith both input #nd output 'unction!. In # TWO-WAY-STREAM e?ery re#d you per'or* 6ill return d#t# re#d 'ro* the underlying input !tre#*, #nd e?ery 6rite 6ill !end d#t# to the underlying output !tre#*. %n ECHO-STREAM 6or9! e!!enti#lly the !#*e 6#y e.cept th#t #ll the d#t# re#d 'ro* the underlying input !tre#* i! #l!o echoed to the output !tre#*. &hu!, the output !tre#* o' #n ECHO-STREAM !tre#* 6ill cont#in # tr#n!cript o' both !ide! o' the con?er!#tion. 8!ing the!e 'i?e 9ind! o' !tre#*!, you c#n build #l*o!t #ny topology o' !tre#* plu*bing you 6#nt. /in#lly, #lthough the Co**on i!p !t#nd#rd doe!n@t !#y #nything #bout net6or9ing %PI!, *o!t i*ple*ent#tion! !upport !oc9et progr#**ing #nd typic#lly i*ple*ent !oc9et! #! #nother 9ind o' !tre#*, !o you c#n u!e #ll the regul#r I;5 'unction! 6ith the*.15 :o6 you@re re#dy to *o?e on to building # libr#ry th#t !*oothe! o?er !o*e o' the di''erence! bet6een ho6 the b#!ic p#thn#*e 'unction! beh#?e in di''erent Co**on i!p i*ple*ent#tion!.
1:ote,
ho6e?er, th#t 6hile the i!p re#der 9no6! ho6 to !9ip co**ent!, it co*pletely !9ip! the*.
&hu!, i' you u!e READ to re#d in # con'igur#tion 'ile cont#ining co**ent! #nd then u!e PRINT to !#?e ch#nge! to the d#t#, you@ll lo!e the co**ent!.
27y
de'#ult OPEN u!e! the de'#ult ch#r#cter encoding 'or the oper#ting !y!te*, but it #l!o #ccept! # 9ey6ord p#r#*eter, :e)ternal-(ormat, th#t c#n p#!! i*ple*ent#tion-de'ined ?#lue! th#t !peci'y # di''erent encoding. Ch#r#cter !tre#*! #l!o tr#n!l#te the pl#t'or*-!peci'ic end-o'-line !eFuence to the !ingle ch#r#cter NY8ewline.
3&he
type 1'nsigned-b?te#R3 indic#te! #n ,-bit byteG Co**on i!p HbyteH type! #ren@t # 'i.ed !iAe !ince i!p h#! run #t ?#riou! ti*e! on #rchitecture! 6ith byte !iAe! 'ro* 0 to ) bit!, to !#y nothing o' the P+P-10, 6hich h#d indi?idu#lly #ddre!!#ble ?#ri#ble-length bit 'ield! o' 1 to 30 bit!.
-In
gener#l, # !tre#* i! either # ch#r#cter !tre#* or # bin#ry !tre#*, !o you c#n@t *i. c#ll! to READBYTE #nd READ-CHAR or other ch#r#cter-b#!ed re#d 'unction!. >o6e?er, !o*e i*ple*ent#tion!, !uch #! %llegro, !upport !o-c#lled bi?#lent !tre#*!, 6hich !upport both ch#r#cter #nd bin#ry I;5.
5So*e
'ol9! e.pect thi! 6ouldn@t be # proble* in # g#rb#ge-collected l#ngu#ge !uch #! i!p. It i! the c#!e in *o!t i!p i*ple*ent#tion! th#t # !tre#* th#t beco*e! g#rb#ge 6ill #uto*#tic#lly be clo!ed. >o6e?er, thi! i!n@t !o*ething to rely on--the proble* i! th#t g#rb#ge collector! u!u#lly run only 6hen *e*ory i! lo6G they don@t 9no6 #bout other !c#rce re!ource! !uch #! 'ile h#ndle!. I' there@! plenty o' *e*ory #?#il#ble, it@! e#!y to run out o' 'ile h#ndle! long be'ore the g#rb#ge collector run!.
0%nother
re#!on the p#thn#*e !y!te* i! con!idered !o*e6h#t b#roFue i! bec#u!e o' the inclu!ion o' logical pathnames. >o6e?er, you c#n u!e the re!t o' the p#thn#*e !y!te* per'ectly 6ell 6ithout 9no6ing #nything *ore #bout logic#l p#thn#*e! th#n th#t you c#n !#'ely ignore the*. 7rie'ly, logic#l p#thn#*e! #llo6 Co**on i!p progr#*! to cont#in re'erence! to p#thn#*e! 6ithout n#*ing !peci'ic 'ile!. ogic#l p#thn#*e! could then be *#pped to !peci'ic loc#tion! in #n #ctu#l 'ile !y!te* 6hen the progr#* 6#! in!t#lled by de'ining # Hlogic#l p#thn#*e tr#n!l#tionH th#t tr#n!l#te! logic#l p#thn#*e! *#tching cert#in 6ildc#rd! to p#thn#*e! repre!enting 'ile! in the 'ile !y!te*, !o-c#lled phy!ic#l p#thn#*e!. &hey h#?e their u!e! in cert#in !itu#tion!, but you c#n get pretty '#r 6ithout 6orrying #bout the*.
23#ny
8ni.-b#!ed i*ple*ent#tion! tre#t 'ilen#*e! 6ho!e l#!t ele*ent !t#rt! 6ith # dot #nd don@t cont#in #ny other dot! !peci#lly, putting the 6hole ele*ent, 6ith the dot, in the n#*e co*ponent #nd le#?ing the type co*ponent NIL.
1pathname-name#1pathname#4/(oo/.emacs433#==/#4.emacs4 1pathname-t?pe#1pathname#4/(oo/.emacs433#==/#89L
>o6e?er, not #ll i*ple*ent#tion! 'ollo6 thi! con?entionG !o*e 6ill cre#te # p#thn#*e 6ith HH #! the n#*e #nd emacs #! the type.
,&he )&he
n#*e returned by FILE-NAMESTRING #l!o include! the ?er!ion co*ponent on 'ile !y!te*! th#t u!e it. ho!t co*ponent *#y not de'#ult to NIL, but i' not, it 6ill be #n op#Fue i*ple*ent#tion-de'ined ?#lue.
10/or
1ma&e-pathname#:t?pe#4html4#:version#:newest#:de(a'lts#inp't-(ile3
Without the :version #rgu*ent, on # 'ile !y!te* 6ith built-in ?er!ioning, the output p#thn#*e 6ould inherit it! ?er!ion nu*ber 'ro* the input 'ile 6hich i!n@t li9ely to be right--i' the input 'ile h#!
been !#?ed *#ny ti*e! it 6ill h#?e # *uch higher ?er!ion nu*ber th#n the gener#ted >&3 'ile. 5n i*ple*ent#tion! 6ithout 'ile ?er!ioning, the :version #rgu*ent !hould be ignored. It@! up to you i' you c#re th#t *uch #bout port#bility.
11See 12/or
#pplic#tion! th#t need #cce!! to other 'ile #ttribute! on # p#rticul#r oper#ting !y!te* or 'ile !y!te*, libr#rie! pro?ide binding! to underlying C !y!te* c#ll!. &he 5!ic#t libr#ry #t http://common-lisp.net/project/osicat/ pro?ide! # !i*ple %PI built u!ing the 8ni?er!#l /oreign /unction Inter'#ce B8//IC, 6hich !hould run on *o!t Co**on i!p! th#t run on # P5SIN oper#ting !y!te*.
13&he
nu*ber o' byte! #nd ch#r#cter! in # 'ile c#n di''er e?en i' you@re not u!ing # *ultibyte ch#r#cter encoding. 7ec#u!e ch#r#cter !tre#*! #l!o tr#n!l#te pl#t'or*-!peci'ic line ending! to # !ingle NY8ewline ch#r#cter, on Windo6! B6hich u!e! C$ / #! it! line endingC the nu*ber o' ch#r#cter! 6ill typic#lly be !*#ller th#n the nu*ber o' byte!. I' you re#lly h#?e to 9no6 the nu*ber o' ch#r#cter! in # 'ile, you h#?e to bite the bullet #nd 6rite !o*ething li9e thi!:
1with-open-(ile#1in#(ilename3 ##1loop#while#1read-char#in#nil3#co'nt#t33
15&he
bigge!t *i!!ing piece in Co**on i!p@! !t#nd#rd I;5 '#cilitie! i! # 6#y 'or u!er! to de'ine ne6 !tre#* cl#!!e!. &here #re, ho6e?er, t6o de '#cto !t#nd#rd! 'or u!er-de'ined !tre#*!. +uring the Co**on i!p !t#nd#rdiA#tion, +#?id =r#y o' &e.#! In!tru*ent! 6rote # dr#'t propo!#l 'or #n %PI to #llo6 u!er! to de'ine ne6 !tre#* cl#!!e!. 8n'ortun#tely, there 6#!n@t ti*e to 6or9 out #ll the i!!ue! r#i!ed by hi! dr#'t to include it in the l#ngu#ge !t#nd#rd. >o6e?er, *#ny i*ple*ent#tion! !upport !o*e 'or* o' !o-c#lled =r#y Stre#*!, b#!ing their %PI on =r#y@! dr#'t propo!#l. %nother, ne6er %PI, c#lled Si*ple Stre#*!, h#! been de?eloped by /r#nA #nd included in %llegro Co**on i!p. It 6#! de!igned to i*pro?e the per'or*#nce o' u!er-de'ined !tre#*! rel#ti?e to =r#y Stre#*! #nd h#! been #dopted by !o*e o' the open-!ource Co**on i!p i*ple*ent#tion!.
The A"I
&he b#!ic oper#tion! the libr#ry 6ill !upport 6ill be getting # li!t o' 'ile! in # directory #nd deter*ining 6hether # 'ile or directory 6ith # gi?en n#*e e.i!t!. 4ou@ll #l!o 6rite # 'unction 'or recur!i?ely 6#l9ing # directory hier#rchy, c#lling # gi?en 'unction 'or e#ch p#thn#*e in the tree. In theory, the!e directory li!ting #nd 'ile e.i!tence oper#tion! #re #lre#dy pro?ided by the !t#nd#rd 'unction! DIRECTORY #nd PROBE-FILE. >o6e?er, #! you@ll !ee, there #re enough di''erent 6#y! to i*ple*ent the!e 'unction!--#ll 6ithin the bound! o' ?#lid interpret#tion! o' the l#ngu#ge !t#nd#rd--th#t you@ll 6#nt to 6rite ne6 'unction! th#t pro?ide # con!i!tent beh#?ior #cro!! i*ple*ent#tion!.
In %llegro th#t code 6ill be re#d #! i' it h#d been 6ritten li9e thi!:
1de('n#(oo#13 ##1do-one-thing33
6hile in #n i*ple*ent#tion other th#n one o' the one! !peci'ic#lly condition#liAed, it 6ill re#d thi!:
1de('n#(oo#13 ##1error#48ot#implemented433
7ec#u!e the condition#liA#tion h#ppen! in the re#der, the co*piler doe!n@t e?en !ee e.pre!!ion! th#t #re !9ipped.1 &hi! *e#n! you p#y no runti*e co!t 'or h#?ing di''erent ?er!ion! 'or di''erent i*ple*ent#tion!. %l!o, 6hen the re#der !9ip! condition#liAed e.pre!!ion!, it doe!n@t bother interning !y*bol!, !o the !9ipped e.pre!!ion! c#n !#'ely cont#in !y*bol! 'ro* p#c9#ge! th#t *#y not e.i!t in other i*ple*ent#tion!. P#c9#ging the ibr#ry Spe#9ing o' p#c9#ge!, i' you do6nlo#d the co*plete code 'or thi! libr#ry, you@ll !ee th#t it@! de'ined in # ne6 p#c9#ge, com.gigamon&e?s.pathnames. I@ll di!cu!! the det#il! o' de'ining #nd u!ing p#c9#ge! in Ch#pter 21. /or no6 you !hould note th#t !o*e i*ple*ent#tion! pro?ide their o6n p#c9#ge! th#t cont#in 'unction! 6ith !o*e o' the !#*e n#*e! #! the one! you@ll de'ine in thi! ch#pter #nd *#9e tho!e n#*e! #?#il#ble in the C -8S($ p#c9#ge. &hu!, i' you try to de'ine the 'unction! 'ro* thi! libr#ry 6hile in the C -8S($ p#c9#ge, you *#y get error! or 6#rning! #bout clobbering e.i!ting de'inition!. &o #?oid thi! po!!ibility, you c#n cre#te # 'ile c#lled pac&ages.lisp 6ith the 'ollo6ing content!:
1in-pac&age#:cl-'ser3 1de(pac&age#:com.gigamon&e?s.pathnames ##1:'se#:common-lisp3 ##1:e)port ###:list-director? ###:(ile-e)ists-p ###:director?-pathname-p ###:(ile-pathname-p ###:pathname-as-director? ###:pathname-as-(ile ###:wal&-director? ###:director?-p ###:(ile-p33
#nd LOAD it. &hen #t the $(P or #t the top o' the 'ile 6here you type the de'inition! 'ro* thi! ch#pter, type the 'ollo6ing e.pre!!ion:
1in-pac&age#:com.gigamon&e?s.pathnames3
In #ddition to #?oiding n#*e con'lict! 6ith !y*bol! #lre#dy #?#il#ble in $L-+,-., p#c9#ging the libr#ry thi! 6#y #l!o *#9e! it e#!ier to u!e in other code, #! you@ll !ee in !e?er#l 'uture ch#pter!.
Listing a 1irectory
4ou c#n i*ple*ent the 'unction 'or li!ting # !ingle directory, list-director?, #! # thin 6r#pper #round the !t#nd#rd 'unction DIRECTORY. DIRECTORY t#9e! # !peci#l 9ind o' p#thn#*e, c#lled # wild pathname, th#t h#! one or *ore co*ponent! cont#ining the !peci#l ?#lue :wild #nd return! # li!t o' p#thn#*e! repre!enting 'ile! in the 'ile !y!te* th#t *#tch the 6ild p#thn#*e.2 &he *#tching #lgorith*--li9e *o!t thing! h#?ing to do 6ith the inter#ction bet6een i!p #nd # p#rticul#r 'ile !y!te*--i!n@t de'ined by the l#ngu#ge !t#nd#rd, but *o!t i*ple*ent#tion! on 8ni. #nd Windo6! 'ollo6 the !#*e b#!ic !che*e. &he DIRECTORY 'unction h#! t6o proble*! th#t you need to #ddre!! 6ith list-director?. &he *#in one i! th#t cert#in #!pect! o' it! beh#?ior di''er '#irly !igni'ic#ntly bet6een di''erent Co**on i!p i*ple*ent#tion!, e?en on the !#*e oper#ting !y!te*. &he other i! th#t 6hile DIRECTORY pro?ide! # po6er'ul inter'#ce 'or li!ting 'ile!, to u!e it properly reFuire! under!t#nding !o*e r#ther !ubtle point! #bout the p#thn#*e #b!tr#ction. 7et6een the!e !ubtletie! #nd the idio!yncr#!ie! o' di''erent i*ple*ent#tion!, #ctu#lly 6riting port#ble code th#t u!e! DIRECTORY to do !o*ething #! !i*ple #! li!ting #ll the 'ile! #nd !ubdirectorie! in # !ingle directory c#n be # 'ru!tr#ting e.perience. 4ou c#n de#l 6ith tho!e !ubtletie! #nd idio!yncr#!ie! once #nd 'or #ll, by 6riting list-director?, #nd 'orget the* there#'ter. 5ne !ubtlety I di!cu!!ed in Ch#pter 1- i! the t6o 6#y! to repre!ent the n#*e o' # directory #! # p#thn#*e: directory 'or* #nd 'ile 'or*. &o get DIRECTORY to return # li!t o' 'ile! in /home/peter/, you need to p#!! it # 6ild p#thn#*e 6ho!e directory co*ponent i! the directory you 6#nt to li!t #nd 6ho!e n#*e #nd type co*ponent! #re :wild. &hu!, to get # li!ting o' the 'ile! in /home/peter/, it *ight !ee* you could 6rite thi!:
1director?#1ma&e-pathname#:name#:wild#:t?pe#:wild#:de(a'lts#home-dir33
6here home-dir i! # p#thn#*e repre!enting /home/peter/. &hi! 6ould 6or9 i' home-dir 6ere in directory 'or*. 7ut i' it 6ere in 'ile 'or*--'or e.#*ple, i' it h#d been cre#ted by p#r!ing the n#*e!tring 4/home/peter4--then th#t !#*e e.pre!!ion 6ould li!t #ll the 'ile! in /home !ince the n#*e co*ponent 4peter4 6ould be repl#ced 6ith :wild. &o #?oid h#?ing to 6orry #bout e.plicitly con?erting bet6een repre!ent#tion!, you c#n de'ine listdirector? to #ccept # non6ild p#thn#*e in either 'or*, 6hich it 6ill then con?ert to the #ppropri#te 6ild p#thn#*e. &o help 6ith thi!, you !hould de'ine # 'e6 helper 'unction!. 5ne, component-present-p, 6ill te!t 6hether # gi?en co*ponent o' # p#thn#*e i! Hpre!ent,H *e#ning neither NIL nor the !peci#l ?#lue :'nspeci(ic.3 %nother, director?-pathname-p, te!t! 6hether # p#thn#*e i! #lre#dy in directory 'or*, #nd the third, pathname-as-director?, con?ert! #ny p#thn#*e to # directory 'or* p#thn#*e.
1de('n#component-present-p#1val'e3 ##1and#val'e#1not#1e@l#val'e#:'nspeci(ic3333 1de('n#director?-pathname-p##1p3 ##1and ###1not#1component-present-p#1pathname-name#p333
###1not#1component-present-p#1pathname-t?pe#p333 ###p33 1de('n#pathname-as-director?#1name3 ##1let#11pathname#1pathname#name333 ####1when#1wild-pathname-p#pathname3 ######1error#4$anCt#reliabl?#convert#wild#pathnames.433 ####1i(#1not#1director?-pathname-p#name33 ######1ma&e-pathname #######:director?#1append#1or#1pathname-director?#pathname3#1list#:relative33 ##########################1list#1(ile-namestring#pathname333 #######:name######nil #######:t?pe######nil #######:de(a'lts#pathname3 ######pathname333
:o6 it !ee*! you could gener#te # 6ild p#thn#*e to p#!! to DIRECTORY by c#lling MA+EPATHNAME 6ith # directory 'or* n#*e returned by pathname-as-director?. 8n'ortun#tely, it@! not Fuite th#t !i*ple, th#n9! to # Fuir9 in C ISP@! i*ple*ent#tion o' DIRECTORY. In C ISP, DIRECTORY 6on@t return 'ile! 6ith no e.ten!ion unle!! the type co*ponent o' the 6ildc#rd i! NIL r#ther th#n :wild. So you c#n de'ine # 'unction, director?-wildcard, th#t t#9e! # p#thn#*e in either directory or 'ile 'or* #nd return! # proper 6ildc#rd 'or the gi?en i*ple*ent#tion u!ing re#d-ti*e condition#liA#tion to *#9e # p#thn#*e 6ith # :wild type co*ponent in #ll i*ple*ent#tion! e.cept 'or C ISP #nd NIL in C ISP.
1de('n#director?-wildcard#1dirname3 ##1ma&e-pathname ###:name#:wild ###:t?pe#N-clisp#:wild#N2clisp#nil ###:de(a'lts#1pathname-as-director?#dirname333
:ote ho6 e#ch re#d-ti*e condition#l oper#te! #t the le?el o' # !ingle e.pre!!ion %'ter N-clisp, the e.pre!!ion :wild i! either re#d or !9ippedG li9e6i!e, #'ter N2clisp, the NIL i! re#d or !9ipped. :o6 you c#n t#9e # 'ir!t cr#c9 #t the list-director? 'unction.
1de('n#list-director?#1dirname3 ##1when#1wild-pathname-p#dirname3 ####1error#4$an#onl?#list#concrete#director?#names.433 ##1director?#1director?-wildcard#dirname333
%! it !t#nd!, thi! 'unction 6ould 6or9 in S7C , C38C , #nd i!pWor9!. 8n'ortun#tely, # couple *ore i*ple*ent#tion di''erence! re*#in to be !*oothed o?er. 5ne i! th#t not #ll i*ple*ent#tion! 6ill return !ubdirectorie! o' the gi?en directory. %llegro, S7C , C38C , #nd i!pWor9! do. 5pen3C doe!n@t by de'#ult but 6ill i' you p#!! DIRECTORY # true ?#lue ?i# the i*ple*ent#tion-!peci'ic 9ey6ord #rgu*ent :directories. C ISP@! DIRECTORY return! !ubdirectorie! only 6hen it@! p#!!ed # 6ildc#rd p#thn#*e 6ith :wild #! the l#!t ele*ent o' the directory co*ponent #nd NIL n#*e #nd type co*ponent!. In thi! c#!e, it return! onl0 !ubdirectorie!, !o you@ll need to c#ll DIRECTORY t6ice 6ith di''erent 6ildc#rd! #nd co*bine the re!ult!. 5nce you get #ll the i*ple*ent#tion! returning directorie!, you@ll di!co?er they c#n #l!o di''er in 6hether they return the n#*e! o' directorie! in directory or 'ile 'or*. 4ou 6#nt list-director? to #l6#y! return directory n#*e! in directory 'or* !o you c#n di''erenti#te !ubdirectorie! 'ro* regul#r 'ile! b#!ed on <u!t the n#*e. (.cept 'or %llegro, #ll the i*ple*ent#tion! thi! libr#ry 6ill !upport do
th#t. %llegro, on the other h#nd, reFuire! you to p#!! DIRECTORY the i*ple*ent#tion-!peci'ic 9ey6ord #rgu*ent :directories-are-(iles NIL to get it to return directorie! in 'ile 'or*. 5nce you 9no6 ho6 to *#9e e#ch i*ple*ent#tion do 6h#t you 6#nt, #ctu#lly 6riting listdirector? i! !i*ply # *#tter o' co*bining the di''erent ?er!ion! u!ing re#d-ti*e condition#l!.
1de('n#list-director?#1dirname3 ##1when#1wild-pathname-p#dirname3 ####1error#4$an#onl?#list#concrete#director?#names.433 ##1let#11wildcard#1director?-wildcard#dirname333 ####N21or#sbcl#cm'#lispwor&s3 ####1director?#wildcard3 ####N2openmcl ####1director?#wildcard#:directories#t3 ####N2allegro ####1director?#wildcard#:directories-are-(iles#nil3 ####N2clisp ####1nconc #####1director?#wildcard3 #####1director?#1clisp-s'bdirectories-wildcard#wildcard333 ####N-1or#sbcl#cm'#lispwor&s#openmcl#allegro#clisp3 ####1error#4list-director?#not#implemented4333
&he 'unction clisp-s'bdirectories-wildcard i!n@t #ctu#lly !peci'ic to C ISP, but !ince it i!n@t needed by #ny other i*ple*ent#tion, you c#n gu#rd it! de'inition 6ith # re#d-ti*e condition#l. In thi! c#!e, !ince the e.pre!!ion 'ollo6ing the N2 i! the 6hole DEFUN, the 6hole 'unction de'inition 6ill be included or not, depending on 6hether clisp i! pre!ent in *FEATURES*.
N2clisp 1de('n#clisp-s'bdirectories-wildcard#1wildcard3 ##1ma&e-pathname ###:director?#1append#1pathname-director?#wildcard3#1list#:wild33 ###:name#nil ###:t?pe#nil ###:de(a'lts#wildcard33
o' # directory in either 'or* but, in!te#d o' returning # directory 'or* n#*e, !i*ply return the n#*e in the !#*e 'or* #! the #rgu*ent it 6#! p#!!ed. uc9ily, i' p#!!ed the n#*e o' # nondirectory in directory 'or*, they return NIL. So 6ith tho!e i*ple*ent#tion! you c#n get the beh#?ior you 6#nt by 'ir!t p#!!ing the n#*e to PROBE-FILE in directory 'or*--i' the 'ile e.i!t! #nd i! # directory, it 6ill return the directory 'or* n#*e. I' th#t c#ll return! NIL, then you try #g#in 6ith # 'ile 'or* n#*e. C ISP, on the other h#nd, once #g#in h#! it! o6n 6#y o' doing thing!. It! PROBE-FILE i**edi#tely !ign#l! #n error i' p#!!ed # n#*e in directory 'or*, reg#rdle!! o' 6hether # 'ile or directory e.i!t! 6ith th#t n#*e. It #l!o !ign#l! #n error i' p#!!ed # n#*e in 'ile 'or* th#t@! #ctu#lly the n#*e o' # directory. /or te!ting 6hether # directory e.i!t!, C ISP pro?ide! it! o6n 'unction: probe-director? Bin the e)t p#c9#geC. &hi! i! #l*o!t the *irror i*#ge o' PROBE-FILE: it !ign#l! #n error i' p#!!ed # n#*e in 'ile 'or* or i' p#!!ed # n#*e in directory 'or* th#t h#ppen! to n#*e # 'ile. &he only di''erence i! it return! T r#ther th#n # p#thn#*e 6hen the n#*ed directory e.i!t!. 7ut e?en in C ISP you c#n i*ple*ent the de!ired !e*#ntic! by 6r#pping the c#ll! to PROBE-FILE #nd probe-director? in IGNORE-ERRORS.1de('n#(ile-e)ists-p#1pathname3 ##N21or#sbcl#lispwor&s#openmcl3 ##1probe-(ile#pathname3 ##N21or#allegro#cm'3 ##1or#1probe-(ile#1pathname-as-director?#pathname33 ######1probe-(ile#pathname33 ##N2clisp ##1or#1ignore-errors ########1probe-(ile#1pathname-as-(ile#pathname333 ######1ignore-errors ########1let#11director?-(orm#1pathname-as-director?#pathname333 ##########1when#1e)t:probe-director?#director?-(orm3 ############director?-(orm3333 ##N-1or#sbcl#cm'#lispwor&s#openmcl#allegro#clisp3 ##1error#4(ile-e)ists-p#not#implemented433
&he 'unction pathname-as-(ile th#t you need 'or the C ISP i*ple*ent#tion o' (ilee)ists-p i! the in?er!e o' the pre?iou!ly de'ined pathname-as-director?, returning # p#thn#*e th#t@! the 'ile 'or* eFui?#lent o' it! #rgu*ent. &hi! 'unction, de!pite being needed here only by C ISP, i! gener#lly u!e'ul, !o de'ine it 'or #ll i*ple*ent#tion! #nd *#9e it p#rt o' the libr#ry.
1de('n#pathname-as-(ile#1name3 ##1let#11pathname#1pathname#name333 ####1when#1wild-pathname-p#pathname3 ######1error#4$anCt#reliabl?#convert#wild#pathnames.433 ####1i(#1director?-pathname-p#name3 ######1letU#11director?#1pathname-director?#pathname33 #############1name-and-t?pe#1pathname#1(irst#1last#director?33333 ########1ma&e-pathname #########:director?#1b'tlast#director?3 #########:name#1pathname-name#name-and-t?pe3 #########:t?pe#1pathname-t?pe#name-and-t?pe3 #########:de(a'lts#pathname33 ######pathname333
:o6 you h#?e # u!e'ul libr#ry o' 'unction! 'or de#ling 6ith p#thn#*e!. %! I *entioned, the!e 'unction! 6ill co*e in h#ndy in l#ter ch#pter!, p#rticul#rly Ch#pter! 23 #nd 22, 6here you@ll u!e wal&director? to cr#6l through directory tree! cont#ining !p#* *e!!#ge! #nd 3P3 'ile!. 7ut be'ore 6e get to th#t, though, I need to t#l9 #bout ob<ect orient#tion, the topic o' the ne.t t6o ch#pter!.
15ne
!lightly #nnoying con!eFuence o' the 6#y re#d-ti*e condition#liA#tion 6or9! i! th#t there@! no e#!y 6#y to 6rite # '#ll-through c#!e. /or e.#*ple, i' you #dd !upport 'or #nother i*ple*ent#tion to (oo by #dding #nother e.pre!!ion gu#rded 6ith N2, you need to re*e*ber to #l!o #dd the !#*e 'e#ture to the or 'e#ture e.pre!!ion #'ter the N- or the ERROR 'or* 6ill be e?#lu#ted #'ter your ne6 code run!.
2%nother
!peci#l ?#lue, :wild-in(eriors, c#n #ppe#r #! p#rt o' the directory co*ponent o' # 6ild p#thn#*e, but you 6on@t need it in thi! ch#pter.
3I*ple*ent#tion! -&hi!
#re #llo6ed to return :'nspeci(ic in!te#d o' NIL #! the ?#lue o' p#thn#*e co*ponent! in cert#in !itu#tion! !uch #! 6hen the co*ponent i!n@t u!ed by th#t i*ple*ent#tion. i! !lightly bro9en in the !en!e th#t i' PROBE-FILE !ign#l! #n error 'or !o*e other re#!on, thi! code 6ill interpret it incorrectly. 8n'ortun#tely, the C ISP docu*ent#tion doe!n@t !peci'y 6h#t error! *ight be !ign#led by PROBE-FILE #nd probe-director?, #nd e.peri*ent#tion !ee*! to !ho6 th#t they !ign#l simple-(ile-error! in *o!t erroneou! !itu#tion!.
orient#tion.2 I' you h#?e little ob<ect-oriented progr#**ing e.perience, you !hould h#?e no trouble under!t#nding the e.pl#n#tion! here, though it *#y help to ignore the occ#!ion#l co*p#ri!on! to the 6#y other l#ngu#ge! do thing!.
3ore !igni'ic#ntly, bec#u!e *ethod! 6eren@t 'unction!, they couldn@t be p#!!ed #! #rgu*ent! to higherorder 'unction! !uch #! MAPCARG i' one 6#nted to c#ll # *ethod on #ll the ele*ent! o' # li!t 6ith MAPCAR, one h#d to 6rite thi!:
1mapcar#NC1lambda#1object3#1send#object#C(oo33#objects3
(?entu#lly the 'ol9! 6or9ing on i!p ob<ect !y!te*! uni'ied *ethod! 6ith 'unction! by cre#ting # ne6 9ind o' 'unction c#lled # generic function. In #ddition to !ol?ing the proble*! <u!t de!cribed, generic 'unction! opened up ne6 po!!ibilitie! 'or the ob<ect !y!te*, including *#ny 'e#ture! th#t !i*ply don@t *#9e !en!e in # *e!!#ge-p#!!ing ob<ect !y!te*. =eneric 'unction! #re the he#rt o' Co**on i!p@! ob<ect !y!te* #nd the topic o' the re!t o' thi! ch#pter. While I c#n@t t#l9 #bout generic 'unction! 6ithout !o*e *ention o' cl#!!e!, 'or no6 I@ll 'ocu! on ho6 to de'ine #nd u!e generic 'unction!. In the ne.t ch#pter I@ll !ho6 you ho6 to de'ine your o6n cl#!!e!.
I@ll di!cu!! the !ynt#. o' DEFGENERIC in the ne.t !ectionG 'or no6 <u!t note th#t thi! de'inition doe!n@t cont#in #ny #ctu#l code. % generic 'unction i! generic in the !en!e th#t it c#n--#t le#!t in theory--#ccept #ny ob<ect! #! #rgu*ent!.5 >o6e?er, by it!el' # generic 'unction c#n@t #ctu#lly do #nythingG i' you <u!t de'ine # generic 'unction, no *#tter 6h#t #rgu*ent! you c#ll it 6ith, it 6ill !ign#l #n error. &he #ctu#l i*ple*ent#tion o' # generic 'unction i! pro?ided by methods. (#ch *ethod pro?ide! #n i*ple*ent#tion o' the generic 'unction 'or p#rticul#r cl#!!e! o' #rgu*ent!. Perh#p! the bigge!t di''erence bet6een # generic 'unction-b#!ed !y!te* #nd # *e!!#ge-p#!!ing !y!te* i! th#t *ethod! don@t belong to cl#!!e!G they belong to the generic 'unction, 6hich i! re!pon!ible 'or deter*ining 6h#t *ethod or *ethod! to run in re!pon!e to # p#rticul#r in?oc#tion. 3ethod! indic#te 6h#t 9ind! o' #rgu*ent! they c#n h#ndle by speciali6ing the reFuired p#r#*eter! de'ined by the generic 'unction. /or in!t#nce, on the generic 'unction draw, you *ight de'ine one *ethod th#t !peci#liAe! the shape p#r#*eter 'or ob<ect! th#t #re in!t#nce! o' the cl#!! circle 6hile #nother *ethod !peci#liAe! shape 'or ob<ect! th#t #re in!t#nce! o' the cl#!! triangle. &hey 6ould loo9 li9e thi!, eliding the #ctu#l dr#6ing code:
1de(method#draw#11shape#circle33 ##...3 1de(method#draw#11shape#triangle33 ##...3
When # generic 'unction i! in?o9ed, it co*p#re! the #ctu#l #rgu*ent! it 6#! p#!!ed 6ith the
!peci#liAer! o' e#ch o' it! *ethod! to 'ind the applicable *ethod!--tho!e *ethod! 6ho!e !peci#liAer! #re co*p#tible 6ith the #ctu#l #rgu*ent!. I' you in?o9e draw, p#!!ing #n in!t#nce o' circle, the *ethod th#t !peci#liAed shape on the cl#!! circle i! #pplic#ble, 6hile i' you p#!! it # triangle, then the *ethod th#t !peci#liAe! shape on the cl#!! triangle #pplie!. In !i*ple c#!e!, only one *ethod 6ill be #pplic#ble, #nd it 6ill h#ndle the in?oc#tion. In *ore co*ple. c#!e!, there *#y be *ultiple *ethod! th#t #pplyG they@re then co*bined, #! I@ll di!cu!! in the !ection H3ethod Co*bin#tion,H into # !ingle effective method th#t h#ndle! the in?oc#tion. 4ou c#n !peci#liAe # p#r#*eter in t6o 6#y!--u!u#lly you@ll !peci'y # cl#!! th#t the #rgu*ent *u!t be #n in!t#nce o'. 7ec#u!e in!t#nce! o' # cl#!! #re #l!o con!idered in!t#nce! o' th#t cl#!!@! !upercl#!!e!, # *ethod 6ith # p#r#*eter !peci#liAed on # p#rticul#r cl#!! c#n be #pplic#ble 6hene?er the corre!ponding #rgu*ent i! # direct in!t#nce o' the !peci#liAing cl#!! or o' #ny o' it! !ubcl#!!e!. &he other 9ind o' !peci#liAer i! # !o-c#lled EQL !peci#liAer, 6hich !peci'ie! # p#rticul#r ob<ect to 6hich the *ethod #pplie!. When # generic 'unction h#! only *ethod! !peci#liAed on # !ingle p#r#*eter #nd #ll the !peci#liAer! #re cl#!! !peci#liAer!, the re!ult o' in?o9ing # generic 'unction i! Fuite !i*il#r to the re!ult o' in?o9ing # *ethod in # *e!!#ge-p#!!ing !y!te*--the co*bin#tion o' the n#*e o' the oper#tion #nd the cl#!! o' the ob<ect on 6hich it@! in?o9ed deter*ine! 6h#t *ethod to run. >o6e?er, re?er!ing the order o' loo9up open! up po!!ibilitie! not 'ound in *e!!#ge-p#!!ing !y!te*!. =eneric 'unction! !upport *ethod! th#t !peci#liAe on *ultiple p#r#*eter!, pro?ide # 'r#*e6or9 th#t *#9e! *ultiple inherit#nce *uch *ore *#n#ge#ble, #nd let you u!e decl#r#ti?e con!truct! to control ho6 *ethod! #re co*bined into #n e''ecti?e *ethod, !upporting !e?er#l co**on u!#ge p#ttern! 6ithout # lot o' boilerpl#te code. I@ll di!cu!! tho!e topic! in # *o*ent. 7ut 'ir!t you need to loo9 #t the b#!ic! o' the t6o *#cro! u!ed to de'ine the generic 'unction! DEFGENERIC #nd DEFMETHOD.
1!F&!:!RI#
&o gi?e you # 'eel 'or the!e *#cro! #nd the ?#riou! '#cilitie! they !upport, I@ll !ho6 you !o*e code you *ight 6rite #! p#rt o' # b#n9ing #pplic#tion--or, r#ther, # toy b#n9ing #pplic#tionG the point i! to loo9 #t # 'e6 l#ngu#ge 'e#ture!, not to le#rn ho6 to re#lly 6rite b#n9ing !o't6#re. /or in!t#nce, thi! code doe!n@t e?en pretend to de#l 6ith !uch i!!ue! #! *ultiple currencie! let #lone #udit tr#il! #nd tr#n!#ction#l integrity. 7ec#u!e I@* not going to di!cu!! ho6 to de'ine ne6 cl#!!e! until the ne.t ch#pter, 'or no6 you c#n <u!t #!!u*e th#t cert#in cl#!!e! #lre#dy e.i!t: 'or !t#rter!, #!!u*e there@! # cl#!! ban&-acco'nt #nd th#t it h#! t6o !ubcl#!!e!, chec&ing-acco'nt #nd savings-acco'nt. &he cl#!! hier#rchy loo9! li9e thi!:
&he 'ir!t generic 'unction 6ill be withdraw, 6hich decre#!e! the #ccount b#l#nce by # !peci'ied #*ount. I' the b#l#nce i! le!! th#n the #*ount, it !hould !ign#l #n error #nd le#?e the b#l#nce
unch#nged. 4ou c#n !t#rt by de'ining the generic 'unction 6ith DEFGENERIC. &he b#!ic 'or* o' DEFGENERIC i! !i*il#r to DEFUN e.cept 6ith no body. &he p#r#*eter li!t o' DEFGENERIC !peci'ie! the p#r#*eter! th#t *u!t be #ccepted by #ll the *ethod! th#t 6ill be de'ined on the generic 'unction. In the pl#ce o' the body, # DEFGENERIC c#n cont#in ?#riou! option!. 5ne option you !hould #l6#y! include i! :doc'mentation, 6hich you u!e to pro?ide # !tring de!cribing the purpo!e o' the generic 'unction. 7ec#u!e # generic 'unction i! purely #b!tr#ct, it@! i*port#nt to be cle#r to both u!er! #nd i*ple*enter! 6h#t it@! 'or. &hu!, you *ight de'ine withdraw li9e thi!:
1de(generic#withdraw#1acco'nt#amo'nt3 ##1:doc'mentation#4Withdraw#the#speci(ied#amo'nt#(rom#the#acco'nt. ,ignal#an#error#i(#the#c'rrent#balance#is#less#than#amo'nt.433
1!F+!T.71
:o6 you@re re#dy to u!e DEFMETHOD to de'ine *ethod! th#t i*ple*ent withdraw.0 % *ethod@! p#r#*eter li!t *u!t be congruent 6ith it! generic 'unction@!. In thi! c#!e, th#t *e#n! #ll *ethod! de'ined on withdraw *u!t h#?e e.#ctly t6o reFuired p#r#*eter!. 3ore gener#lly, *ethod! *u!t h#?e the !#*e nu*ber o' reFuired #nd option#l p#r#*eter! #nd *u!t be c#p#ble o' #ccepting #ny #rgu*ent! corre!ponding to #ny &&'(! or &)'* p#r#*eter! !peci'ied by the generic 'unction.2 Since the b#!ic! o' 6ithdr#6ing #re the !#*e 'or #ll #ccount!, you c#n de'ine # *ethod th#t !peci#liAe! the acco'nt p#r#*eter on the ban&-acco'nt cl#!!. 4ou c#n #!!u*e the 'unction balance return! the current b#l#nce o' the #ccount #nd c#n be u!ed 6ith SETF--#nd thu! 6ith DECF--to !et the b#l#nce. &he 'unction ERROR i! # !t#nd#rd 'unction u!ed to !ign#l #n error, 6hich I@ll di!cu!! in gre#ter det#il in Ch#pter 1). 8!ing tho!e t6o 'unction!, you c#n de'ine # b#!ic withdraw *ethod th#t loo9! li9e thi!:
1de(method#withdraw#11acco'nt#ban&-acco'nt3#amo'nt3 ##1when#1O#1balance#acco'nt3#amo'nt3 ####1error#4Icco'nt#overdrawn.433 ##1dec(#1balance#acco'nt3#amo'nt33
%! thi! code !ugge!t!, the 'or* o' DEFMETHOD i! e?en *ore li9e th#t o' DEFUN th#n DEFGENERIC@! i!. &he only di''erence i! th#t the reFuired p#r#*eter! c#n be !peci#liAed by repl#cing the p#r#*eter n#*e 6ith # t6o-ele*ent li!t. &he 'ir!t ele*ent i! the n#*e o' the p#r#*eter, #nd the !econd ele*ent i! the !peci#liAer, either the n#*e o' # cl#!! or #n EQL !peci#liAer, the 'or* o' 6hich I@ll di!cu!! in # *o*ent. &he p#r#*eter n#*e c#n be #nything--it doe!n@t h#?e to *#tch the n#*e u!ed in the generic 'unction, though it o'ten 6ill. &hi! *ethod 6ill #pply 6hene?er the 'ir!t #rgu*ent to withdraw i! #n in!t#nce o' ban&-acco'nt. &he !econd p#r#*eter, amo'nt, i! i*plicitly !peci#liAed on T, #nd !ince #ll ob<ect! #re in!t#nce! o' T, it doe!n@t #''ect the #pplic#bility o' the *ethod. :o6 !uppo!e #ll chec9ing #ccount! h#?e o?erdr#'t protection. &h#t i!, e#ch chec9ing #ccount i! lin9ed to #nother b#n9 #ccount th#t@! dr#6n upon 6hen the b#l#nce o' the chec9ing #ccount it!el' c#n@t co?er # 6ithdr#6#l. 4ou c#n #!!u*e th#t the 'unction overdra(t-acco'nt t#9e! # chec&ingacco'nt ob<ect #nd return! # ban&-acco'nt ob<ect repre!enting the lin9ed #ccount. &hu!, 6ithdr#6ing 'ro* # chec&ing-acco'nt ob<ect reFuire! # 'e6 e.tr# !tep! co*p#red to 6ithdr#6ing 'ro* # !t#nd#rd ban&-acco'nt ob<ect. 4ou *u!t 'ir!t chec9 6hether the #*ount being 6ithdr#6n i! gre#ter th#n the #ccount@! current b#l#nce #nd, i' it i!, tr#n!'er the di''erence 'ro* the
o?erdr#'t #ccount. &hen you c#n proceed #! 6ith # !t#nd#rd ban&-acco'nt ob<ect. So 6h#t you@d li9e to do i! de'ine # *ethod on withdraw th#t !peci#liAe! on chec&ing-acco'nt to h#ndle the tr#n!'er #nd then let! the *ethod !peci#liAed on ban&-acco'nt t#9e control. Such # *ethod *ight loo9 li9e thi!:
1de(method#withdraw#11acco'nt#chec&ing-acco'nt3#amo'nt3 ##1let#11overdra(t#1-#amo'nt#1balance#acco'nt3333 ####1when#1pl'sp#overdra(t3 ######1withdraw#1overdra(t-acco'nt#acco'nt3#overdra(t3 ######1inc(#1balance#acco'nt3#overdra(t333 ##1call-ne)t-method33
&he 'unction CALL-NEXT-METHOD i! p#rt o' the generic 'unction *#chinery u!ed to co*bine #pplic#ble *ethod!. It indic#te! th#t control !hould be p#!!ed 'ro* thi! *ethod to the *ethod !peci#liAed on ban&-acco'nt., When it@! c#lled 6ith no #rgu*ent!, #! it i! here, the ne.t *ethod i! in?o9ed 6ith 6h#te?er #rgu*ent! 6ere origin#lly p#!!ed to the generic 'unction. It c#n #l!o be c#lled 6ith #rgu*ent!, 6hich 6ill then be p#!!ed onto the ne.t *ethod. 4ou #ren@t reFuired to in?o9e CALL-NEXT-METHOD in e?ery *ethod. >o6e?er, i' you don@t, the ne6 *ethod i! then re!pon!ible 'or co*pletely i*ple*enting the de!ired beh#?ior o' the generic 'unction. /or e.#*ple, i' you h#d # !ubcl#!! o' ban&-acco'nt, pro)?-acco'nt, th#t didn@t #ctu#lly 9eep tr#c9 o' it! o6n b#l#nce but in!te#d deleg#ted 6ithdr#6#l! to #nother #ccount, you *ight 6rite # *ethod li9e thi! B#!!u*ing # 'unction, pro)ied-acco'nt, th#t return! the pro.ied #ccountC:
1de(method#withdraw#11pro)?#pro)?-acco'nt3#amo'nt3 ##1withdraw#1pro)ied-acco'nt#pro)?3#amo'nt33
/in#lly, DEFMETHOD #l!o #llo6! you to cre#te *ethod! !peci#liAed on # p#rticul#r ob<ect 6ith #n EQL !peci#liAer. /or e.#*ple, !uppo!e the b#n9ing #pp i! going to be deployed in # p#rticul#rly corrupt b#n9. Suppo!e the ?#ri#ble Uacco'nt-o(-ban&-presidentU hold! # re'erence to # p#rticul#r b#n9 #ccount th#t belong!--#! the n#*e !ugge!t!--to the b#n9@! pre!ident. /urther !uppo!e the ?#ri#ble Uban&U repre!ent! the b#n9 #! # 6hole, #nd the 'unction embe**le !te#l! *oney 'ro* the b#n9. &he b#n9 pre!ident *ight #!9 you to H'i.H withdraw to h#ndle hi! #ccount !peci#lly.
1de(method#withdraw#11acco'nt#1e@l#Uacco'nt-o(-ban&-presidentU33#amo'nt3 ##1let#11overdra(t#1-#amo'nt#1balance#acco'nt3333 ####1when#1pl'sp#overdra(t3 ######1inc(#1balance#acco'nt3#1embe**le#Uban&U#overdra(t333 ##1call-ne)t-method333
:ote, ho6e?er, th#t the 'or* in the EQL !peci#liAer th#t pro?ide! the ob<ect to !peci#liAe on-Uacco'nt-o(-ban&-presidentU in thi! c#!e--i! e?#lu#ted once, 6hen the DEFMETHOD i! e?#lu#ted. &hi! *ethod 6ill be !peci#liAed on the ?#lue o' Uacco'nt-o(-ban&-presidentU #t the ti*e the *ethod i! de'inedG ch#nging the ?#ri#ble l#ter 6on@t ch#nge the *ethod.
+ethod #o$2ination
5ut!ide the body o' # *ethod, CALL-NEXT-METHOD h#! no *e#ning. Within # *ethod, it@! gi?en # *e#ning by the generic 'unction *#chinery th#t build! #n effective method e#ch ti*e the generic 'unction i! in?o9ed u!ing #ll the *ethod! #pplic#ble to th#t p#rticul#r in?oc#tion. &hi! notion o' building #n e''ecti?e *ethod by co*bining #pplic#ble *ethod! i! the he#rt o' the generic 'unction concept #nd i! the thing th#t #llo6! generic 'unction! to !upport '#cilitie! not 'ound in *e!!#ge-p#!!ing
!y!te*!. So it@! 6orth t#9ing # clo!er loo9 #t 6h#t@! re#lly h#ppening. /ol9! 6ith the *e!!#ge-p#!!ing *odel deeply ingr#ined in their con!ciou!ne!! !hould p#y p#rticul#r #ttention bec#u!e generic 'unction! turn *ethod di!p#tching in!ide out co*p#red to *e!!#ge p#!!ing, *#9ing the generic 'unction, r#ther th#n the cl#!!, the pri*e *o?er. Conceptu#lly, the e''ecti?e *ethod i! built in three !tep!: /ir!t, the generic 'unction build! # li!t o' #pplic#ble *ethod! b#!ed on the #ctu#l #rgu*ent! it 6#! p#!!ed. Second, the li!t o' #pplic#ble *ethod! i! !orted #ccording to the specificit0 o' their p#r#*eter !peci#liAer!. /in#lly, *ethod! #re t#9en in order 'ro* the !orted li!t #nd their code co*bined to produce the e''ecti?e *ethod.) &o 'ind #pplic#ble *ethod!, the generic 'unction co*p#re! the #ctu#l #rgu*ent! 6ith the corre!ponding p#r#*eter !peci#liAer! in e#ch o' it! *ethod!. % *ethod i! #pplic#ble i', #nd only i', #ll the !peci#liAer! #re co*p#tible 6ith the corre!ponding #rgu*ent!. When the !peci#liAer i! the n#*e o' # cl#!!, it@! co*p#tible i' it n#*e! the #ctu#l cl#!! o' the #rgu*ent or one o' it! !upercl#!!e!. B$ec#ll th#t p#r#*eter! 6ithout e.plicit !peci#liAer! #re i*plicitly !peci#liAed on the cl#!! T !o 6ill be co*p#tible 6ith #ny #rgu*ent.C %n EQL !peci#liAer i! co*p#tible only 6hen the #rgu*ent i! the !#*e ob<ect #! 6#! !peci'ied in the !peci#liAer. 7ec#u!e all the #rgu*ent! #re chec9ed #g#in!t the corre!ponding !peci#liAer!, they #ll #''ect 6hether # *ethod i! #pplic#ble. 3ethod! th#t e.plicitly !peci#liAe *ore th#n one p#r#*eter #re c#lled multimethodsG I@ll di!cu!! the* in the !ection H3ulti*ethod!.H %'ter the #pplic#ble *ethod! h#?e been 'ound, the generic 'unction *#chinery need! to !ort the* be'ore it c#n co*bine the* into #n e''ecti?e *ethod. &o order t6o #pplic#ble *ethod!, the generic 'unction co*p#re! their p#r#*eter !peci#liAer! 'ro* le't to right,10 #nd the 'ir!t !peci#liAer th#t@! di''erent bet6een the t6o *ethod! deter*ine! their ordering, 6ith the *ethod 6ith the *ore !peci'ic !peci#liAer co*ing 'ir!t. 7ec#u!e only #pplic#ble *ethod! #re being !orted, you 9no6 #ll cl#!! !peci#liAer! 6ill n#*e cl#!!e! th#t the corre!ponding #rgu*ent i! #ctu#lly #n in!t#nce o'. In the typic#l c#!e, i' t6o cl#!! !peci#liAer! di''er, one 6ill be # !ubcl#!! o' the other. In th#t c#!e, the !peci#liAer n#*ing the !ubcl#!! i! con!idered *ore !peci'ic. &hi! i! 6hy the *ethod th#t !peci#liAed acco'nt on chec&ing-acco'nt 6#! con!idered *ore !peci'ic th#n the *ethod th#t !peci#liAed it on ban&-acco'nt. 3ultiple inherit#nce !lightly co*plic#te! the notion o' !peci'icity !ince the #ctu#l #rgu*ent *#y be #n in!t#nce o' t6o cl#!!e!, neither o' 6hich i! # !ubcl#!! o' the other. I' !uch cl#!!e! #re u!ed #! p#r#*eter !peci#liAer!, the generic 'unction c#n@t order the* u!ing only the rule th#t !ubcl#!!e! #re *ore !peci'ic th#n their !upercl#!!e!. In the ne.t ch#pter I@ll di!cu!! ho6 the notion o' !peci'icity i! e.tended to de#l 6ith *ultiple inherit#nce. /or no6, !u''ice it to !#y th#t there@! # deter*ini!tic #lgorith* 'or ordering cl#!! !peci#liAer!. /in#lly, #n EQL !peci#liAer i! #l6#y! *ore !peci'ic th#n #ny cl#!! !peci#liAer, #nd bec#u!e only #pplic#ble *ethod! #re being con!idered, i' *ore th#n one *ethod h#! #n EQL !peci#liAer 'or # p#rticul#r p#r#*eter, they *u!t #ll h#?e the !#*e EQL !peci#liAer. &he co*p#ri!on o' tho!e *ethod! 6ill thu! be decided b#!ed on other p#r#*eter!.
!peci'ic *ethod run! 'ir!t, #nd e#ch *ethod c#n p#!! control to the ne.t *o!t !peci'ic *ethod ?i# CALL-NEXT-METHOD. >o6e?er, there@! # bit *ore to it th#n th#t. &he *ethod! I@?e been di!cu!!ing !o '#r #re c#lled primar0 methods. Pri*#ry *ethod!, #! their n#*e !ugge!t!, #re re!pon!ible 'or pro?iding the pri*#ry i*ple*ent#tion o' # generic 'unction. &he !t#nd#rd *ethod co*bin#tion #l!o !upport! three 9ind! o' au3iliar0 *ethod!: :be(ore, :a(ter, #nd :aro'nd *ethod!. %n #u.ili#ry *ethod de'inition i! 6ritten 6ith DEFMETHOD li9e # pri*#ry *ethod but 6ith # method 4ualifier< 6hich n#*e! the type o' *ethod, bet6een the n#*e o' the *ethod #nd the p#r#*eter li!t. /or in!t#nce, # :be(ore *ethod on withdraw th#t !peci#liAe! the acco'nt p#r#*eter on the cl#!! ban&-acco'nt 6ould !t#rt li9e thi!:
1de(method#withdraw#:be(ore#11acco'nt#ban&-acco'nt3#amo'nt3#...3
(#ch 9ind o' #u.ili#ry *ethod i! co*bined into the e''ecti?e *ethod in # di''erent 6#y. %ll the #pplic#ble :be(ore *ethod!--not <u!t the *o!t !peci'ic--#re run #! p#rt o' the e''ecti?e *ethod. &hey run, #! their n#*e !ugge!t!, be'ore the *o!t !peci'ic pri*#ry *ethod #nd #re run in *o!t-!peci'ic-'ir!t order. &hu!, :be(ore *ethod! c#n be u!ed to do #ny prep#r#tion needed to en!ure th#t the pri*#ry *ethod c#n run. /or in!t#nce, you could@?e u!ed # :be(ore *ethod !peci#liAed on chec&ingacco'nt to i*ple*ent the o?erdr#'t protection on chec9ing #ccount! li9e thi!:
1de(method#withdraw#:be(ore#11acco'nt#chec&ing-acco'nt3#amo'nt3 ##1let#11overdra(t#1-#amo'nt#1balance#acco'nt3333 ####1when#1pl'sp#overdra(t3 ######1withdraw#1overdra(t-acco'nt#acco'nt3#overdra(t3 ######1inc(#1balance#acco'nt3#overdra(t3333
&hi! :be(ore *ethod h#! three #d?#nt#ge! o?er # pri*#ry *ethod. 5ne i! th#t it *#9e! it i**edi#tely ob?iou! ho6 the *ethod ch#nge! the o?er#ll beh#?ior o' the withdraw 'unction--it@! not going to inter'ere 6ith the *#in beh#?ior or ch#nge the re!ult returned. &he ne.t #d?#nt#ge i! th#t # pri*#ry *ethod !peci#liAed on # cl#!! *ore !peci'ic th#n chec&ingacco'nt 6on@t inter'ere 6ith thi! :be(ore *ethod, *#9ing it e#!ier 'or #n #uthor o' # !ubcl#!! o' chec&ing-acco'nt to e.tend the beh#?ior o' withdraw 6hile 9eeping p#rt o' the old beh#?ior. #!tly, !ince # :be(ore *ethod doe!n@t h#?e to c#ll CALL-NEXT-METHOD to p#!! control to the re*#ining *ethod!, it@! i*po!!ible to introduce # bug by 'orgetting to. &he other #u.ili#ry *ethod! #l!o 'it into the e''ecti?e *ethod in 6#y! !ugge!ted by their n#*e!. %ll the :a(ter *ethod! run #'ter the pri*#ry *ethod! in *o!t-!peci'ic-l#!t order, th#t i!, the re?er!e o' the :be(ore *ethod!. &hu!, the :be(ore #nd :a(ter *ethod! co*bine to cre#te # !ort o' ne!ted 6r#pping #round the core 'unction#lity pro?ided by the pri*#ry *ethod!--e#ch *ore-!peci'ic :be(ore *ethod 6ill get # ch#nce to !et thing! up !o the le!!-!peci'ic :be(ore *ethod! #nd pri*#ry *ethod! c#n run !ucce!!'ully, #nd e#ch *ore-!peci'ic :a(ter *ethod 6ill get # ch#nce to cle#n up #'ter #ll the pri*#ry *ethod! #nd le!!-!peci'ic :a(ter *ethod!. /in#lly, :aro'nd *ethod! #re co*bined *uch li9e pri*#ry *ethod! e.cept they@re run H#roundH #ll the other *ethod!. &h#t i!, the code 'ro* the *o!t !peci'ic :aro'nd *ethod i! run be'ore #nything el!e. Within the body o' #n :aro'nd *ethod, CALL-NEXT-METHOD 6ill le#d to the code o' the ne.t *o!t !peci'ic :aro'nd *ethod or, in the le#!t !peci'ic :aro'nd *ethod, to the co*ple. o' :be(ore, pri*#ry, #nd :a(ter *ethod!. %l*o!t #ll :aro'nd *ethod! 6ill cont#in !uch # c#ll to CALL-NEXT-METHOD bec#u!e #n :aro'nd *ethod th#t doe!n@t 6ill co*pletely hi<#c9 the i*ple*ent#tion o' the generic 'unction 'ro* #ll the *ethod! e.cept 'or *ore-!peci'ic :aro'nd
*ethod!. 5cc#!ion#lly th#t 9ind o' hi<#c9ing i! c#lled 'or, but typic#lly :aro'nd *ethod! #re u!ed to e!t#bli!h !o*e dyn#*ic conte.t in 6hich the re!t o' the *ethod! 6ill run--to bind # dyn#*ic ?#ri#ble, 'or e.#*ple, or to e!t#bli!h #n error h#ndler B#! I@ll di!cu!! in Ch#pter 1)C. %bout the only ti*e it@! #ppropri#te 'or #n :aro'nd *ethod to not c#ll CALL-NEXT-METHOD i! 6hen it return! # re!ult c#ched 'ro* # pre?iou! c#ll to CALL-NEXT-METHOD. %t #ny r#te, #n :aro'nd *ethod th#t doe!n@t c#ll CALL-NEXT-METHOD i! re!pon!ible 'or correctly i*ple*enting the !e*#ntic! o' the generic 'unction 'or #ll cl#!!e! o' #rgu*ent! to 6hich the *ethod *#y #pply, including 'uture !ubcl#!!e!. %u.ili#ry *ethod! #re <u!t # con?enient 6#y to e.pre!! cert#in co**on p#ttern! *ore conci!ely #nd concretely. &hey don@t #ctu#lly #llo6 you to do #nything you couldn@t do by co*bining pri*#ry *ethod! 6ith diligent #dherence to # 'e6 coding con?ention! #nd !o*e e.tr# typing. Perh#p! their bigge!t bene'it i! th#t they pro?ide # uni'or* 'r#*e6or9 'or e.tending generic 'unction!. 5'ten # libr#ry 6ill de'ine # generic 'unction #nd pro?ide # de'#ult pri*#ry *ethod, #llo6ing u!er! o' the libr#ry to cu!to*iAe it! beh#?ior by de'ining #ppropri#te #u.ili#ry *ethod!.
7y de'#ult #ll the!e *ethod co*bin#tion! co*bine the pri*#ry *ethod! in *o!t-!peci'ic-'ir!t order. >o6e?er, you c#n re?er!e the order by including the 9ey6ord :most-speci(ic-last #'ter the
n#*e o' the *ethod co*bin#tion in the DEFGENERIC 'or*. &he order prob#bly doe!n@t *#tter i' you@re u!ing the + co*bin#tion unle!! the *ethod! h#?e !ide e''ect!, but 'or de*on!tr#tion purpo!e! you c#n ch#nge priorit? to u!e *o!t-!peci'ic-l#!t order li9e thi!:
1de(generic#priorit?#1job3 ##1:doc'mentation#4.et'rn#the#priorit?#at#which#the#job#sho'ld#be#r'n.43 ##1:method-combination#2#:most-speci(ic-last33
&he pri*#ry *ethod! on # generic 'unction th#t u!e! one o' the!e co*bin#tion! *u!t be Fu#li'ied 6ith the n#*e o' the *ethod co*bin#tion. &hu!, # pri*#ry *ethod de'ined on priorit? *ight loo9 li9e thi!:
1de(method#priorit?#2#11job#e)press-job33#0 3
&hi! *#9e! it ob?iou! 6hen you !ee # *ethod de'inition th#t it@! p#rt o' # p#rticul#r 9ind o' generic 'unction. %ll the !i*ple built-in *ethod co*bin#tion! #l!o !upport :aro'nd *ethod! th#t 6or9 li9e :aro'nd *ethod! in the !t#nd#rd *ethod co*bin#tion: the *o!t !peci'ic :aro'nd *ethod run! be'ore #ny other *ethod!, #nd CALL-NEXT-METHOD i! u!ed to p#!! control to le!!-#nd-le!!-!peci'ic :aro'nd *ethod! until it re#che! the co*bined pri*#ry *ethod!. &he :most-speci(ic-last option doe!n@t #''ect the order o' :aro'nd *ethod!. %nd, #! I *entioned be'ore, the built-in *ethod co*bin#tion! don@t !upport :be(ore or :a(ter *ethod!. i9e the !t#nd#rd *ethod co*bin#tion, the!e *ethod co*bin#tion! don@t #llo6 you to do #nything you couldn@t do Hby h#nd.H $#ther, they #llo6 you to e.pre!! what you 6#nt #nd let the l#ngu#ge t#9e c#re o' 6iring e?erything together 'or you, *#9ing your code both *ore conci!e #nd *ore e.pre!!i?e. &h#t !#id, prob#bly )) percent o' the ti*e, the !t#nd#rd *ethod co*bin#tion 6ill be e.#ctly 6h#t you 6#nt. 5' the re*#ining 1 percent, prob#bly )) percent o' the* 6ill be h#ndled by one o' the !i*ple built-in *ethod co*bin#tion!. I' you run into one o' the 1 percent o' 1 percent o' c#!e! 6here none o' the built-in co*bin#tion! !u''ice!, you c#n loo9 up DEFINE-METHOD-COMBINATION in your '#?orite Co**on i!p re'erence.
+u%ti$ethods
3ethod! th#t e.plicitly !peci#liAe *ore th#n one o' the generic 'unction@! reFuired p#r#*eter! #re c#lled multimethods. 3ulti*ethod! #re 6here generic 'unction! #nd *e!!#ge p#!!ing re#lly p#rt 6#y!. 3ulti*ethod! don@t 'it into *e!!#ge-p#!!ing l#ngu#ge! bec#u!e they don@t belong to # p#rticul#r cl#!!G in!te#d, e#ch *ulti*ethod de'ine! # p#rt o' the i*ple*ent#tion! o' # gi?en generic 'unction th#t #pplie! 6hen the generic 'unction i! in?o9ed 6ith #rgu*ent! th#t *#tch all the *ethod@! !peci#liAed p#r#*eter!. 3ulti*ethod! ?!. 3ethod 5?erlo#ding Progr#**er! u!ed to !t#tic#lly typed *e!!#ge-p#!!ing l#ngu#ge! !uch #! D#?# #nd CEE *#y thin9 *ulti*ethod! !ound !i*il#r to # 'e#ture o' tho!e l#ngu#ge! c#lled method overloading. >o6e?er, the!e t6o l#ngu#ge 'e#ture! #re #ctu#lly Fuite di''erent !ince o?erlo#ded *ethod! #re cho!en #t co*pile ti*e, b#!ed on the co*pile-ti*e type o' the #rgu*ent!, not #t runti*e. &o !ee ho6 thi! 6or9!, con!ider the 'ollo6ing t6o D#?# cl#!!e!:
p'blic#class#I#V ##p'blic#void#(oo1I#a3#V#,?stem.o't.println14I/I43S#W ##p'blic#void#(oo1L#b3#V#,?stem.o't.println14I/L43S#W
:o6 con!ider 6h#t h#ppen! 6hen you run the main *ethod 'ro* thi! cl#!!.
p'blic#class#%ain#V ##p'blic#static#void#main1,tringDG#argv3#V ####I#obj#=#argvD G.e@'als14I43#?#new#I13#:#new#L13S ####obj.(oo1obj3S ##W W
When you tell %ain to in!t#nti#te #n I, it print! H%;%H #! you@d prob#bly e.pect.
bash\#java#com.gigamon&e?s.%ain#I I/I
>o6e?er, i' you tell %ain to in!t#nti#te # L, then the true type o' obj i! t#9en into #ccount 'or only h#l' the di!p#tching.
bash\#java#com.gigamon&e?s.%ain#L L/I
I' o?erlo#ded *ethod! 6or9ed li9e Co**on i!p@! *ulti*ethod!, then th#t 6ould print H7;7H in!te#d. It i! po!!ible to i*ple*ent *ultiple di!p#tch by h#nd in *e!!#ge-p#!!ing l#ngu#ge!, but thi! run! #g#in!t the gr#in o' the *e!!#ge-p#!!ing *odel !ince the code in # *ultiply di!p#tched *ethod doe!n@t belong to #ny one cl#!!. 3ulti*ethod! #re per'ect 'or #ll tho!e !itu#tion! 6here, in # *e!!#ge-p#!!ing l#ngu#ge, you !truggle to decide to 6hich cl#!! # cert#in beh#?ior ought to belong. I! the !ound # dru* *#9e! 6hen it@! hit 6ith # dru*!tic9 # 'unction o' 6h#t 9ind o' dru* it i! or 6h#t 9ind o' !tic9 you u!e to hit it" 7oth, o' cour!e. &o *odel thi! !itu#tion in Co**on i!p, you !i*ply de'ine # generic 'unction beat th#t t#9e! t6o #rgu*ent!.
1de(generic#beat#1dr'm#stic&3 ##1:doc'mentation ###4Trod'ce#a#so'nd#b?#hitting#the#given#dr'm#with#the#given#stic&.433
&hen you c#n de'ine ?#riou! *ulti*ethod! to i*ple*ent beat 'or the co*bin#tion! you c#re #bout. /or e.#*ple:
1de(method#beat#11dr'm#snare-dr'm3#1stic&#wooden-dr'mstic&33#...3 1de(method#beat#11dr'm#snare-dr'm3#1stic&#br'sh33#...3 1de(method#beat#11dr'm#snare-dr'm3#1stic&#so(t-mallet33#...3 1de(method#beat#11dr'm#tom-tom3#1stic&#wooden-dr'mstic&33#...3 1de(method#beat#11dr'm#tom-tom3#1stic&#br'sh33#...3 1de(method#beat#11dr'm#tom-tom3#1stic&#so(t-mallet33#...3
3ulti*ethod! don@t help 6ith the co*bin#tori#l e.plo!ion--i' you need to *odel 'i?e 9ind! o' dru*! #nd !i. 9ind! o' !tic9!, #nd e?ery co*bin#tion *#9e! # di''erent !ound, there@! no 6#y #round itG you need thirty di''erent *ethod! to i*ple*ent #ll the co*bin#tion!, 6ith or 6ithout *ulti*ethod!. Wh#t *ulti*ethod! do !#?e you 'ro* i! h#?ing to 6rite # bunch o' di!p#tching code by letting you u!e the
!#*e built-in poly*orphic di!p#tching th#t@! !o u!e'ul 6hen de#ling 6ith *ethod! !peci#liAed on # !ingle p#r#*eter.11 3ulti*ethod! #l!o !#?e you 'ro* h#?ing to tightly couple one !et o' cl#!!e! 6ith the other. In the dru*;!tic9 e.#*ple, nothing reFuire! the i*ple*ent#tion o' the dru* cl#!!e! to 9no6 #bout the ?#riou! cl#!!e! o' dru*!tic9, #nd nothing reFuire! the dru*!tic9 cl#!!e! to 9no6 #nything #bout the ?#riou! cl#!!e! o' dru*. &he *ulti*ethod! connect the other6i!e independent cl#!!e! to de!cribe their <oint beh#?ior 6ithout reFuiring #ny cooper#tion 'ro* the cl#!!e! the*!el?e!.
To Be #ontinued . . .
I@?e co?ered the b#!ic!--#nd # bit beyond--o' generic 'unction!, the ?erb! o' Co**on i!p@! ob<ect !y!te*. In the ne.t ch#pter I@ll !ho6 you ho6 to de'ine your o6n cl#!!e!.
1&he
l#ngu#ge no6 gener#lly con!idered the 'ir!t ob<ect-oriented l#ngu#ge, Si*ul#, 6#! in?ented in the e#rly 1)00!, only # 'e6 ye#r! #'ter 3cC#rthy@! 'ir!t i!p. >o6e?er, ob<ect orient#tion didn@t re#lly t#9e o'' until the 1),0! 6hen the 'ir!t 6idely #?#il#ble ?er!ion o' S*#llt#l9 6#! rele#!ed, 'ollo6ed by the rele#!e o' CEE # 'e6 ye#r! l#ter. S*#llt#l9 too9 Fuite # bit o' in!pir#tion 'ro* i!p #nd co*bined it 6ith ide#! 'ro* Si*ul# to produce # dyn#*ic ob<ect-oriented l#ngu#ge, 6hile CEE co*bined Si*ul# 6ith C, #nother '#irly !t#tic l#ngu#ge, to yield # !t#tic ob<ect-oriented l#ngu#ge. &hi! e#rly !plit h#! led to *uch con'u!ion in the de'inition o' ob<ect orient#tion. /ol9! 6ho co*e 'ro* the CEE tr#dition tend to con!ider cert#in #!pect! o' CEE, !uch #! !trict d#t# enc#p!ul#tion, to be 9ey ch#r#cteri!tic! o' ob<ect orient#tion. /ol9! 'ro* the S*#llt#l9 tr#dition, ho6e?er, con!ider *#ny 'e#ture! o' CEE to be <u!t th#t, 'e#ture! o' CEE, #nd not core to ob<ect orient#tion. Indeed, %l#n L#y, the in?entor o' S*#llt#l9, i! reported to h#?e !#id, HI in?ented the ter* object oriented, #nd I c#n tell you th#t CEE 6#!n@t 6h#t I h#d in *ind.H
2&here
#re tho!e 6ho re<ect the notion th#t Co**on i!p i! in '#ct ob<ect oriented #t #ll. In p#rticul#r, 'ol9! 6ho con!ider !trict d#t# enc#p!ul#tion # 9ey ch#r#cteri!tic o' ob<ect orient#tion--u!u#lly #d?oc#te! o' rel#ti?ely !t#tic l#ngu#ge! !uch #! CEE, (i''el, or D#?#--don@t con!ider Co**on i!p to be properly ob<ect oriented. 5' cour!e, by th#t de'inition, S*#llt#l9, #rgu#bly one o' the origin#l #nd pure!t ob<ect-oriented l#ngu#ge!, i!n@t ob<ect oriented either. 5n the other h#nd, 'ol9! 6ho con!ider *e!!#ge p#!!ing to be the 9ey to ob<ect orient#tion 6ill #l!o not be h#ppy 6ith the cl#i* th#t Co**on i!p i! ob<ect oriented !ince Co**on i!p@! generic 'unction orient#tion pro?ide! degree! o' 'reedo* not o''ered by pure *e!!#ge p#!!ing.
3Prototype-b#!ed
l#ngu#ge! #re the other !tyle o' ob<ect-oriented l#ngu#ge. In the!e l#ngu#ge!, D#?#Script being perh#p! the *o!t '#*ou! e.#*ple, ob<ect! #re cre#ted by cloning # prototypic#l ob<ect. &he clone c#n then be *odi'ied #nd u!ed #! # prototype 'or other ob<ect!.
-T
the con!t#nt ?#lue #nd T the cl#!! h#?e no p#rticul#r rel#tion!hip e.cept they h#ppen to h#?e the !#*e n#*e. T the ?#lue i! # direct in!t#nce o' the cl#!! SYMBOL #nd only indirectly #n in!t#nce o' T the cl#!!.
5>ere,
#! el!e6here, object *e#n! #ny i!p d#tu*--Co**on i!p doe!n@t di!tingui!h, #! !o*e l#ngu#ge! do, bet6een ob<ect! #nd Hpri*iti?eH d#t# type!G #ll d#t# in Co**on i!p #re ob<ect!, #nd e?ery ob<ect i! #n in!t#nce o' # cl#!!.
0&echnic#lly
you could !9ip the DEFGENERIC #ltogether--i' you de'ine # *ethod 6ith DEFMETHOD #nd no !uch generic 'unction h#! been de'ined, one i! #uto*#tic#lly cre#ted. 7ut it@! good 'or* to
de'ine generic 'unction! e.plicitly, i' only bec#u!e it gi?e! you # good pl#ce to docu*ent the intended beh#?ior.
2% *ethod
c#n H#cceptH &)'* #nd &&'(! #rgu*ent! de'ined in it! generic 'unction by h#?ing # &&'(! p#r#*eter, by h#?ing the !#*e &)'* p#r#*eter!, or by !peci'ying &$%%o5-o!6'&-)'*( #long 6ith &)'*. % *ethod c#n #l!o !peci'y &)'* p#r#*eter! not 'ound in the generic 'unction@! p#r#*eter li!t--6hen the generic 'unction i! c#lled, #ny &)'* p#r#*eter !peci'ied by the generic 'unction or #ny #pplic#ble *ethod 6ill be #ccepted.
,CALL-NEXT-METHOD )While
i! roughly #n#logou! to in?o9ing # *ethod on s'per in D#?# or u!ing #n e.plicitly cl#!!-Fu#li'ied *ethod or 'unction n#*e in Python or CEE. building the e''ecti?e *ethod !ound! ti*e-con!u*ing, Fuite # bit o' the e''ort in de?eloping '#!t Co**on i!p i*ple*ent#tion! h#! gone into *#9ing it e''icient. 5ne !tr#tegy i! to c#che the e''ecti?e *ethod !o 'uture c#ll! 6ith the !#*e #rgu*ent type! 6ill be #ble to proceed directly.
10%ctu#lly, 11In
the order in 6hich !peci#liAer! #re co*p#red i! cu!to*iA#ble ?i# the DEFGENERIC option :arg'ment-precedence-order, though th#t option i! r#rely u!ed. l#ngu#ge! 6ithout *ulti*ethod!, you *u!t 6rite di!p#tching code your!el' to i*ple*ent beh#?ior th#t depend! on the cl#!! o' *ore th#n one ob<ect. &he purpo!e o' the popul#r 1i!itor de!ign p#ttern i! to !tructure # !erie! o' !ingly di!p#tched *ethod c#ll! !o #! to pro?ide *ultiple di!p#tch. >o6e?er, it reFuire! one !et o' cl#!!e! to 9no6 #bout the other. &he 1i!itor p#ttern #l!o Fuic9ly bog! do6n in # co*bin#tori#l e.plo!ion o' di!p#tching *ethod! i' it@! u!ed to di!p#tch on *ore th#n t6o ob<ect!.
1!F#LA//
4ou cre#te u!er-de'ined cl#!!e! 6ith the DEFCLASS *#cro. 7ec#u!e beh#?ior! #re #!!oci#ted 6ith # cl#!! by de'ining generic 'unction! #nd *ethod! !peci#liAed on the cl#!!, DEFCLASS i! re!pon!ible only 'or de'ining the cl#!! #! # d#t# type. &he three '#cet! o' the cl#!! #! # d#t# type #re it! n#*e, it! rel#tion to other cl#!!e!, #nd the n#*e! o' the !lot! th#t *#9e up in!t#nce! o' the cl#!!.2 &he b#!ic 'or* o' # DEFCLASS i! Fuite !i*ple.
1de(class#name#1direct-superclass-nameU3 ##1slot-specifierU33
Wh#t %re H8!er-+e'ined Cl#!!e!H" &he ter* user)defined classes i!n@t # ter* 'ro* the l#ngu#ge !t#nd#rd--technic#lly 6h#t I@* t#l9ing #bout 6hen I !#y user)defined classes #re cl#!!e! th#t !ubcl#!! STANDARD-OB4ECT #nd 6ho!e *et#cl#!! i! STANDARD-CLASS. 7ut !ince I@* not going to t#l9 #bout the 6#y! you c#n de'ine cl#!!e! th#t don@t !ubcl#!! STANDARD-OB4ECT #nd 6ho!e *et#cl#!! i!n@t STANDARD-CLASS, you don@t re#lly h#?e to 6orry #bout th#t. "ser)defined i!n@t # per'ect ter* 'or the!e cl#!!e! !ince the i*ple*ent#tion *#y de'ine cert#in cl#!!e! the !#*e 6#y. >o6e?er, to c#ll the* standard cl#!!e! 6ould be e?en *ore con'u!ing !ince the built-in cl#!!e!, !uch #! INTEGER #nd STRING, #re <u!t #! !t#nd#rd, i' not *ore !o, bec#u!e they@re de'ined by the l#ngu#ge !t#nd#rd but they don@t e.tend STANDARDOB4ECT. &o 'urther co*plic#te *#tter!, it@! #l!o po!!ible 'or u!er! to de'ine ne6 cl#!!e! th#t don(t !ubcl#!! STANDARD-OB4ECT. In p#rticul#r, the *#cro DEFSTRUCT #l!o de'ine! ne6 cl#!!e!. 7ut th#t@! l#rgely 'or b#c96#rd co*p#tibility--DEFSTRUCT pred#ted C 5S #nd 6#! retro'itted to de'ine cl#!!e! 6hen C 5S 6#! integr#ted into the l#ngu#ge. 7ut the cl#!!e! it cre#te! #re '#irly li*ited co*p#red to DEFCLASSed cl#!!e!. So in thi! ch#pter I@ll be di!cu!!ing only cl#!!e! de'ined 6ith DEFCLASS th#t u!e the de'#ult *et#cl#!! o' STANDARD-CLASS, #nd I@ll re'er to the* #! user) defined 'or l#c9 o' # better ter*. %! 6ith 'unction! #nd ?#ri#ble!, you c#n u!e #ny !y*bol #! the n#*e o' # ne6 cl#!!.3 Cl#!! n#*e! #re in # !ep#r#te n#*e!p#ce 'ro* both 'unction! #nd ?#ri#ble!, !o you c#n h#?e # cl#!!, 'unction, #nd ?#ri#ble #ll 6ith the !#*e n#*e. 4ou@ll u!e the cl#!! n#*e #! the #rgu*ent to MA+E-INSTANCE, the 'unction th#t cre#te! ne6 in!t#nce! o' u!er-de'ined cl#!!e!. &he direct)superclass)names !peci'y the cl#!!e! o' 6hich the ne6 cl#!! i! # !ubcl#!!. I' no !upercl#!!e! #re li!ted, the ne6 cl#!! 6ill directly !ubcl#!! STANDARD-OB4ECT. %ny cl#!!e! li!ted *u!t be other u!er-de'ined cl#!!e!, 6hich en!ure! th#t e#ch ne6 cl#!! i! ulti*#tely de!cended 'ro* STANDARDOB4ECT. STANDARD-OB4ECT in turn !ubcl#!!e! T, !o #ll u!er-de'ined cl#!!e! #re p#rt o' the !ingle cl#!! hier#rchy th#t #l!o cont#in! #ll the built-in cl#!!e!. (liding the !lot !peci'ier! 'or # *o*ent, the DEFCLASS 'or*! o' !o*e o' the cl#!!e! you u!ed in the pre?iou! ch#pter *ight loo9 li9e thi!:
1de(class#ban&-acco'nt#13#...3 1de(class#chec&ing-acco'nt#1ban&-acco'nt3#...3 1de(class#savings-acco'nt#1ban&-acco'nt3#...3
I@ll di!cu!! in the !ection H3ultiple Inherit#nceH 6h#t it *e#n! to li!t *ore th#n one direct !upercl#!! in direct)superclass)names.
(#ch in!t#nce o' thi! cl#!! 6ill cont#in t6o !lot!, one to hold the n#*e o' the cu!to*er the #ccount belong! to #nd #nother to hold the current b#l#nce. With thi! de'inition, you c#n cre#te ne6 ban&acco'nt ob<ect! u!ing MA+E-INSTANCE.
1ma&e-instance#Cban&-acco'nt3#==/#NOLI8M-I$$;+8F#P#N)Q!4b93ba/
&he #rgu*ent to MA+E-INSTANCE i! the n#*e o' the cl#!! to in!t#nti#te, #nd the ?#lue returned i! the ne6 ob<ect.- &he printed repre!ent#tion o' #n ob<ect i! deter*ined by the generic 'unction PRINTOB4ECT. In thi! c#!e, the #pplic#ble *ethod 6ill be one pro?ided by the i*ple*ent#tion, !peci#liAed on STANDARD-OB4ECT. Since not e?ery ob<ect c#n be printed !o th#t it c#n be re#d b#c9, the STANDARD-OB4ECT print *ethod u!e! the NO/ !ynt#., 6hich 6ill c#u!e the re#der to !ign#l #n error i' it trie! to re#d it. &he re!t o' the repre!ent#tion i! i*ple*ent#tion-de'ined but 6ill typic#lly be !o*ething li9e the output <u!t !ho6n, including the n#*e o' the cl#!! #nd !o*e di!tingui!hing ?#lue !uch #! the #ddre!! o' the ob<ect in *e*ory. In Ch#pter 23 you@ll !ee #n e.#*ple o' ho6 to de'ine # *ethod on PRINT-OB4ECT to *#9e ob<ect! o' # cert#in cl#!! be printed in # *ore in'or*#ti?e 'or*. 8!ing the de'inition o' ban&-acco'nt <u!t gi?en, ne6 ob<ect! 6ill be cre#ted 6ith their !lot! unbound. %ny #tte*pt to get the ?#lue o' #n unbound !lot !ign#l! #n error, !o you *u!t !et # !lot be'ore you c#n re#d it.
1de(parameter#Uacco'ntU#1ma&e-instance#Cban&-acco'nt33##==/#UI$$;+8FU 1set(#1slot-val'e#Uacco'ntU#Cc'stomer-name3#4_ohn#<oe43#==/#4_ohn#<oe4 1set(#1slot-val'e#Uacco'ntU#Cbalance3#0 3#############==/#0
72Aect Initia%i>ation
Since you c#n@t do *uch 6ith #n ob<ect 6ith unbound !lot!, it@d be nice to be #ble to cre#te ob<ect! 6ith their !lot! #lre#dy initi#liAed. Co**on i!p pro?ide! three 6#y! to control the initi#l ?#lue o' !lot!.
&he 'ir!t t6o in?ol?e #dding option! to the !lot !peci'ier in the DEFCLASS 'or*: 6ith the :initarg option, you c#n !peci'y # n#*e th#t c#n then be u!ed #! # 9ey6ord p#r#*eter to MA+E-INSTANCE #nd 6ho!e #rgu*ent 6ill be !tored in the !lot. % !econd option, :init(orm, let! you !peci'y # i!p e.pre!!ion th#t 6ill be u!ed to co*pute # ?#lue 'or the !lot i' no :initarg #rgu*ent i! p#!!ed to MA+E-INSTANCE. /in#lly, 'or co*plete control o?er the initi#liA#tion, you c#n de'ine # *ethod on the generic 'unction INITIALI3E-INSTANCE, 6hich i! c#lled by MA+E-INSTANCE.5 % !lot !peci'ier th#t include! option! !uch #! :initarg or :init(orm i! 6ritten #! # li!t !t#rting 6ith the n#*e o' the !lot 'ollo6ed by the option!. /or e.#*ple, i' you 6#nt to *odi'y the de'inition o' ban&-acco'nt to #llo6 c#ller! o' MA+E-INSTANCE to p#!! the cu!to*er n#*e #nd the initi#l b#l#nce #nd to pro?ide # de'#ult ?#lue o' Aero doll#r! 'or the b#l#nce, you@d 6rite thi!:
1de(class#ban&-acco'nt#13 ##11c'stomer-name ####:initarg#:c'stomer-name3 ###1balance ####:initarg#:balance ####:init(orm# 333
:o6 you c#n cre#te #n #ccount #nd !peci'y the !lot ?#lue! #t the !#*e ti*e.
1de(parameter#Uacco'ntU ##1ma&e-instance#Cban&-acco'nt#:c'stomer-name#4_ohn#<oe4#:balance#0 1slot-val'e#Uacco'ntU#Cc'stomer-name3#==/#4_ohn#<oe4 1slot-val'e#Uacco'ntU#Cbalance3#######==/#0 33
I' you don@t !upply # :balance #rgu*ent to MA+E-INSTANCE, the SLOT-VALUE o' balance 6ill be co*puted by e?#lu#ting the 'or* !peci'ied 6ith the :init(orm option. 7ut i' you don@t !upply # :c'stomer-name #rgu*ent, the c'stomer-name !lot 6ill be unbound, #nd #n #tte*pt to re#d it be'ore you !et it 6ill !ign#l #n error.
1slot-val'e#1ma&e-instance#Cban&-acco'nt3#Cbalance3#######==/# 1slot-val'e#1ma&e-instance#Cban&-acco'nt3#Cc'stomer-name3#==/#error
I' you 6#nt to en!ure th#t the cu!to*er n#*e i! !upplied 6hen the #ccount i! cre#ted, you c#n !ign#l #n error in the init'or* !ince it 6ill be e?#lu#ted only i' #n init#rg i!n@t !upplied. 4ou c#n #l!o u!e init'or*! th#t gener#te # di''erent ?#lue e#ch ti*e they@re e?#lu#ted--the init'or* i! e?#lu#ted #ne6 'or e#ch ob<ect. &o e.peri*ent 6ith the!e techniFue!, you c#n *odi'y the c'stomer-name !lot !peci'ier #nd #dd # ne6 !lot, acco'nt-n'mber, th#t@! initi#liAed 6ith the ?#lue o' #n e?er-incre#!ing counter.
1de(var#Uacco'nt-n'mbersU# 3 1de(class#ban&-acco'nt#13 ##11c'stomer-name ####:initarg#:c'stomer-name ####:init(orm#1error#4%'st#s'ppl?#a#c'stomer#name.433 ###1balance ####:initarg#:balance ####:init(orm# 3 ###1acco'nt-n'mber ####:init(orm#1inc(#Uacco'nt-n'mbersU3333
3o!t o' the ti*e the co*bin#tion o' :initarg #nd :init(orm option! 6ill be !u''icient to properly initi#liAe #n ob<ect. >o6e?er, 6hile #n init'or* c#n be #ny i!p e.pre!!ion, it h#! no #cce!! to
the ob<ect being initi#liAed, !o it c#n@t initi#liAe one !lot b#!ed on the ?#lue o' #nother. /or th#t you need to de'ine # *ethod on the generic 'unction INITIALI3E-INSTANCE. &he pri*#ry *ethod on INITIALI3E-INSTANCE !peci#liAed on STANDARD-OB4ECT t#9e! c#re o' initi#liAing !lot! b#!ed on their :initarg #nd :init(orm option!. Since you don@t 6#nt to di!turb th#t, the *o!t co**on 6#y to #dd cu!to* initi#liA#tion code i! to de'ine #n :a(ter *ethod !peci#liAed on your cl#!!.0 /or in!t#nce, !uppo!e you 6#nt to #dd # !lot acco'nt-t?pe th#t need! to be !et to one o' the ?#lue! :gold, :silver, or :bron*e b#!ed on the #ccount@! initi#l b#l#nce. 4ou *ight ch#nge your cl#!! de'inition to thi!, #dding the acco'nt-t?pe !lot 6ith no option!:
1de(class#ban&-acco'nt#13 ##11c'stomer-name ####:initarg#:c'stomer-name ####:init(orm#1error#4%'st#s'ppl?#a#c'stomer#name.433 ###1balance ####:initarg#:balance ####:init(orm# 3 ###1acco'nt-n'mber ####:init(orm#1inc(#Uacco'nt-n'mbersU33 ###acco'nt-t?pe33
&hen you c#n de'ine #n :a(ter *ethod on INITIALI3E-INSTANCE th#t !et! the acco'ntt?pe !lot b#!ed on the ?#lue th#t h#! been !tored in the balance !lot.2
1de(method#initiali*e-instance#:a(ter#11acco'nt#ban&-acco'nt3#>&e?3 ##1let#11balance#1slot-val'e#acco'nt#Cbalance333 ####1set(#1slot-val'e#acco'nt#Cacco'nt-t?pe3 ##########1cond ############11/=#balance#0 3#:gold3 ############11/=#balance#" 3#:silver3 ############1t#:bron*e33333
&he &)'* in the p#r#*eter li!t i! reFuired to 9eep the *ethod@! p#r#*eter li!t congruent 6ith the generic 'unction@!--the p#r#*eter li!t !peci'ied 'or the INITIALI3E-INSTANCE generic 'unction include! &)'* in order to #llo6 indi?idu#l *ethod! to !upply their o6n 9ey6ord p#r#*eter! but doe!n@t reFuire #ny p#rticul#r one!. &hu!, e?ery *ethod *u!t !peci'y &)'* e?en i' it doe!n@t !peci'y #ny &)'* p#r#*eter!. 5n the other h#nd, i' #n INITIALI3E-INSTANCE *ethod !peci#liAed on # p#rticul#r cl#!! doe! !peci'y # &)'* p#r#*eter, th#t p#r#*eter beco*e! # leg#l p#r#*eter to MA+E-INSTANCE 6hen cre#ting #n in!t#nce o' th#t cl#!!. /or in!t#nce, i' the b#n9 !o*eti*e! p#y! # percent#ge o' the initi#l b#l#nce #! # bonu! 6hen #n #ccount i! opened, you could i*ple*ent th#t u!ing # *ethod on INITIALI3E-INSTANCE th#t t#9e! # 9ey6ord #rgu*ent to !peci'y the percent#ge o' the bonu! li9e thi!:
1de(method#initiali*e-instance#:a(ter#11acco'nt#ban&-acco'nt3 #######################################>&e?#opening-bon's-percentage3 ##1when#opening-bon's-percentage ####1inc(#1slot-val'e#acco'nt#Cbalance3 ##########1U#1slot-val'e#acco'nt#Cbalance3#1/#opening-bon's-percentage#0
33333
7y de'ining thi! INITIALI3E-INSTANCE *ethod, you *#9e :opening-bon's-percentage # leg#l #rgu*ent to MA+E-INSTANCE 6hen cre#ting # ban&-acco'nt ob<ect.
$L-+,-./#1de(parameter#UacctU#1ma&e-instance
Accessor Functions
7et6een MA+E-INSTANCE #nd SLOT-VALUE, you h#?e #ll the tool! you need 'or cre#ting #nd *#nipul#ting in!t#nce! o' your cl#!!e!. (?erything el!e you *ight 6#nt to do c#n be i*ple*ented in ter*! o' tho!e t6o 'unction!. >o6e?er, #! #nyone '#*ili#r 6ith the principle! o' good ob<ect-oriented progr#**ing pr#ctice! 9no6!, directly #cce!!ing the !lot! Bor 'ield! or *e*ber ?#ri#ble!C o' #n ob<ect c#n le#d to 'r#gile code. &he proble* i! th#t directly #cce!!ing !lot! tie! your code too tightly to the concrete !tructure o' your cl#!!. /or e.#*ple, !uppo!e you decide to ch#nge the de'inition o' ban&acco'nt !o th#t, in!te#d o' !toring the current b#l#nce #! # nu*ber, you !tore # li!t o' ti*e-!t#*ped 6ithdr#6#l! #nd depo!it!. Code th#t directly #cce!!e! the balance !lot 6ill li9ely bre#9 i' you ch#nge the cl#!! de'inition to re*o?e the !lot or to !tore the ne6 li!t in the old !lot. 5n the other h#nd, i' you de'ine # 'unction, balance, th#t #cce!!e! the !lot, you c#n rede'ine it l#ter to pre!er?e it! beh#?ior e?en i' the intern#l repre!ent#tion ch#nge!. %nd code th#t u!e! !uch # 'unction 6ill continue to 6or9 6ithout *odi'ic#tion. %nother #d?#nt#ge to u!ing #cce!!or 'unction! r#ther th#n direct #cce!! to !lot! ?i# SLOT-VALUE i! th#t they let you li*it the 6#y! out!ide code c#n *odi'y # !lot., It *#y be 'ine 'or u!er! o' the ban&acco'nt cl#!! to get the current b#l#nce, but you *#y 6#nt #ll *odi'ic#tion! to the b#l#nce to go through other 'unction! you@ll pro?ide, !uch #! deposit #nd withdraw. I' client! 9no6 they@re !uppo!ed to *#nipul#te ob<ect! only through the publi!hed 'unction#l %PI, you c#n pro?ide # balance 'unction but not *#9e it SETF#ble i' you 6#nt the b#l#nce to be re#d-only. /in#lly, u!ing #cce!!or 'unction! *#9e! your code tidier !ince it help! you #?oid lot! o' u!e! o' the r#ther ?erbo!e SLOT-VALUE 'unction. It@! tri?i#l to de'ine # 'unction th#t re#d! the ?#lue o' the balance !lot.
1de('n#balance#1acco'nt3 ##1slot-val'e#acco'nt#Cbalance33
>o6e?er, i' you 9no6 you@re going to de'ine !ubcl#!!e! o' ban&-acco'nt, it *ight be # good ide# to de'ine balance #! # generic 'unction. &h#t 6#y, you c#n pro?ide di''erent *ethod! on balance 'or tho!e !ubcl#!!e! or e.tend it! de'inition 6ith #u.ili#ry *ethod!. So you *ight 6rite thi! in!te#d:
1de(generic#balance#1acco'nt33 1de(method#balance#11acco'nt#ban&-acco'nt33 ##1slot-val'e#acco'nt#Cbalance33
%! I <u!t di!cu!!ed, you don@t 6#nt c#ller! to be #ble to directly !et the b#l#nce, but 'or other !lot!, !uch #! c'stomer-name, you *#y #l!o 6#nt to pro?ide # 'unction to !et the*. &he cle#ne!t 6#y to de'ine !uch # 'unction i! #! # SETF 'unction. % SETF 'unction i! # 6#y to e.tend SETF, de'ining # ne6 9ind o' pl#ce th#t it 9no6! ho6 to !et. &he n#*e o' # SETF 'unction i! # t6o-ite* li!t 6ho!e 'ir!t ele*ent i! the !y*bol set( #nd 6ho!e !econd
ele*ent i! # !y*bol, typic#lly the n#*e o' # 'unction u!ed to #cce!! the pl#ce the SETF 'unction 6ill !et. % SETF 'unction c#n t#9e #ny nu*ber o' #rgu*ent!, but the 'ir!t #rgu*ent i! #l6#y! the ?#lue to be #!!igned to the pl#ce.) 4ou could, 'or in!t#nce, de'ine # SETF 'unction to !et the c'stomer-name# !lot in # ban&-acco'nt li9e thi!:
1de('n#1set(#c'stomer-name3#1name#acco'nt3 ##1set(#1slot-val'e#acco'nt#Cc'stomer-name3#name33
6ill be co*piled #! # c#ll to the SETF 'unction you <u!t de'ined 6ith HS#lly SueH #! the 'ir!t #rgu*ent #nd the ?#lue o' m?-acco'nt #! the !econd #rgu*ent. 5' cour!e, #! 6ith re#der 'unction!, you@ll prob#bly 6#nt your SETF 'unction to be generic, !o you@d #ctu#lly de'ine it li9e thi!:
1de(generic#1set(#c'stomer-name3#1val'e#acco'nt33 1de(method#1set(#c'stomer-name3#1val'e#1acco'nt#ban&-acco'nt33 ##1set(#1slot-val'e#acco'nt#Cc'stomer-name3#val'e33
%nd o' cour!e you@ll #l!o 6#nt to de'ine # re#der 'unction 'or c'stomer-name.
1de(generic#c'stomer-name#1acco'nt33 1de(method#c'stomer-name#11acco'nt#ban&-acco'nt33 ##1slot-val'e#acco'nt#Cc'stomer-name33
&here@! nothing h#rd #bout 6riting the!e #cce!!or 'unction!, but it 6ouldn@t be in 9eeping 6ith &he i!p W#y to h#?e to 6rite the* #ll by h#nd. &hu!, DEFCLASS !upport! three !lot option! th#t #llo6 you to #uto*#tic#lly cre#te re#der #nd 6riter 'unction! 'or # !peci'ic !lot. &he :reader option !peci'ie! # n#*e to be u!ed #! the n#*e o' # generic 'unction th#t #ccept! #n ob<ect #! it! !ingle #rgu*ent. When the DEFCLASS i! e?#lu#ted, the generic 'unction i! cre#ted, i' it doe!n@t #lre#dy e.i!t. &hen # *ethod !peci#liAing it! !ingle #rgu*ent on the ne6 cl#!! #nd returning the ?#lue o' the !lot i! #dded to the generic 'unction. &he n#*e c#n be #nything, but it@! typic#l to n#*e it the !#*e #! the !lot it!el'. &hu!, in!te#d o' e.plicitly 6riting the balance generic 'unction #nd *ethod #! !ho6n pre?iou!ly, you could ch#nge the !lot !peci'ier 'or the balance !lot in the de'inition o' ban&-acco'nt to thi!:
1balance #:initarg#:balance #:init(orm# #:reader#balance3
&he :writer option i! u!ed to cre#te # generic 'unction #nd *ethod 'or !etting the ?#lue o' # !lot. &he 'unction #nd *ethod cre#ted 'ollo6 the reFuire*ent! 'or # SETF 'unction, t#9ing the ne6 ?#lue #!
the 'ir!t #rgu*ent #nd returning it #! the re!ult, !o you c#n de'ine # SETF 'unction by pro?iding # n#*e !uch #! 1set(#c'stomer-name3. /or in!t#nce, you could pro?ide re#der #nd 6riter *ethod! 'or c'stomer-name eFui?#lent to the one! you <u!t 6rote by ch#nging the !lot !peci'ier to thi!:
1c'stomer-name #:initarg#:c'stomer-name #:init(orm#1error#4%'st#s'ppl?#a#c'stomer#name.43 #:reader#c'stomer-name #:writer#1set(#c'stomer-name33
Since it@! Fuite co**on to 6#nt both re#der #nd 6riter 'unction!, DEFCLASS #l!o pro?ide! #n option, :accessor, th#t cre#te! both # re#der 'unction #nd the corre!ponding SETF 'unction. So in!te#d o' the !lot !peci'ier <u!t !ho6n, you@d typic#lly 6rite thi!:
1c'stomer-name #:initarg#:c'stomer-name #:init(orm#1error#4%'st#s'ppl?#a#c'stomer#name.43 #:accessor#c'stomer-name3
/in#lly, one l#!t !lot option you !hould 9no6 #bout i! the :doc'mentation option, 6hich you c#n u!e to pro?ide # !tring th#t docu*ent! the purpo!e o' the !lot. Putting it #ll together #nd #dding # re#der *ethod 'or the acco'nt-n'mber #nd acco'nt-t?pe !lot!, the DEFCLASS 'or* 'or the ban&acco'nt cl#!! 6ould loo9 li9e thi!:
1de(class#ban&-acco'nt#13 ##11c'stomer-name ####:initarg#:c'stomer-name ####:init(orm#1error#4%'st#s'ppl?#a#c'stomer#name.43 ####:accessor#c'stomer-name ####:doc'mentation#4$'stomerCs#name43 ###1balance ####:initarg#:balance ####:init(orm# ####:reader#balance ####:doc'mentation#4$'rrent#acco'nt#balance43 ###1acco'nt-n'mber ####:init(orm#1inc(#Uacco'nt-n'mbersU3 ####:reader#acco'nt-n'mber ####:doc'mentation#4Icco'nt#n'mber5#'ni@'e#within#a#ban&.43 ###1acco'nt-t?pe ####:reader#acco'nt-t?pe ####:doc'mentation#4F?pe#o(#acco'nt5#one#o(#:gold5#:silver5#or#:bron*e.4333
%nd i' you decide you 6#nt to directly #cce!! the !lot ?#lue in order to #?oid running #u.ili#ry *ethod!, it get! e?en *ore cluttered.
1de(method#assess-low-balance-penalt?#11acco'nt#ban&-acco'nt33 ##1when#1O#1slot-val'e#acco'nt#Cbalance3#Uminim'm-balanceU3 ####1dec(#1slot-val'e#acco'nt#Cbalance3#1U#1slot-val'e#acco'nt#Cbalance3#. 03333
&6o !t#nd#rd *#cro!, WITH-SLOTS #nd WITH-ACCESSORS, c#n help tidy up thi! clutter. 7oth *#cro! cre#te # bloc9 o' code in 6hich !i*ple ?#ri#ble n#*e! c#n be u!ed to re'er to !lot! on # p#rticul#r ob<ect. WITH-SLOTS pro?ide! direct #cce!! to the !lot!, #! i' by SLOT-VALUE, 6hile WITH-ACCESSORS pro?ide! # !horth#nd 'or #cce!!or *ethod!. &he b#!ic 'or* o' WITH-SLOTS i! #! 'ollo6!:
1with-slots#1slotU3#instance-form ##body-formU3
(#ch ele*ent o' slots c#n be either the n#*e o' # !lot, 6hich i! #l!o u!ed #! # ?#ri#ble n#*e, or # t6oite* li!t 6here the 'ir!t ite* i! # n#*e to u!e #! # ?#ri#ble #nd the !econd i! the n#*e o' the !lot. &he instance)form i! e?#lu#ted once to produce the ob<ect 6ho!e !lot! 6ill be #cce!!ed. Within the body, e#ch occurrence o' one o' the ?#ri#ble n#*e! i! tr#n!l#ted to # c#ll to SLOT-VALUE 6ith the ob<ect #nd the #ppropri#te !lot n#*e #! #rgu*ent!.10 &hu!, you c#n 6rite assess-low-balancepenalt? li9e thi!:
1de(method#assess-low-balance-penalt?#11acco'nt#ban&-acco'nt33 ##1with-slots#1balance3#acco'nt ####1when#1O#balance#Uminim'm-balanceU3 ######1dec(#balance#1U#balance#. 033333
I' you h#d de'ined balance 6ith #n :accessor r#ther th#n <u!t # :reader, then you could #l!o u!e WITH-ACCESSORS. &he 'or* o' WITH-ACCESSORS i! the !#*e #! WITH-SLOTS e.cept e#ch ele*ent o' the !lot li!t i! # t6o-ite* li!t cont#ining # ?#ri#ble n#*e #nd the n#*e o' #n #cce!!or 'unction. Within the body o' WITH-ACCESSORS, # re'erence to one o' the ?#ri#ble! i! eFui?#lent to # c#ll to the corre!ponding #cce!!or 'unction. I' the #cce!!or 'unction i! SETF#ble, then !o i! the ?#ri#ble.
1de(method#assess-low-balance-penalt?#11acco'nt#ban&-acco'nt33 ##1with-accessors#11balance#balance33#acco'nt ####1when#1O#balance#Uminim'm-balanceU3 ######1dec(#balance#1U#balance#. 033333
&he 'ir!t balance i! the n#*e o' the ?#ri#ble, #nd the !econd i! the n#*e o' the #cce!!or 'unctionG
they don@t h#?e to be the !#*e. 4ou could, 'or in!t#nce, 6rite # *ethod to *erge t6o #ccount! u!ing t6o c#ll! to WITH-ACCESSORS, one 'or e#ch #ccount.
1de(method#merge-acco'nts#11acco'nt0#ban&-acco'nt3#1acco'nt!#ban&-acco'nt33 ##1with-accessors#11balance0#balance33#acco'nt0 ####1with-accessors#11balance!#balance33#acco'nt! ######1inc(#balance0#balance!3 ######1set(#balance!# 3333
&he choice o' 6hether to u!e WITH-SLOTS ?er!u! WITH-ACCESSORS i! the !#*e #! the choice bet6een SLOT-VALUE #nd #n #cce!!or 'unction: lo6-le?el code th#t pro?ide! the b#!ic 'unction#lity o' # cl#!! *#y u!e SLOT-VALUE or WITH-SLOTS to directly *#nipul#te !lot! in 6#y! not !upported by #cce!!or 'unction! or to e.plicitly #?oid the e''ect! o' #u.ili#ry *ethod! th#t *#y h#?e been de'ined on the #cce!!or 'unction!. 7ut you !hould gener#lly u!e #cce!!or 'unction! or WITH-ACCESSORS unle!! you h#?e # !peci'ic re#!on not to.
#%ass4A%%ocated /%ots
&he l#!t !lot option you need to 9no6 #bout i! :allocation. &he ?#lue o' :allocation c#n be either :instance or :class #nd de'#ult! to :instance i' not !peci'ied. When # !lot h#! :class #lloc#tion, the !lot h#! only # !ingle ?#lue, 6hich i! !tored in the cl#!! #nd !h#red by #ll in!t#nce!. >o6e?er, :class !lot! #re #cce!!ed the !#*e #! :instance !lot!--they@re #cce!!ed 6ith SLOTVALUE or #n #cce!!or 'unction, 6hich *e#n! you c#n #cce!! the !lot ?#lue only through #n in!t#nce o' the cl#!! e?en though it i!n@t #ctu#lly !tored in the in!t#nce. &he :init(orm #nd :initarg option! h#?e e!!enti#lly the !#*e e''ect e.cept the init'or* i! e?#lu#ted once 6hen the cl#!! i! de'ined r#ther th#n e#ch ti*e #n in!t#nce i! cre#ted. 5n the other h#nd, p#!!ing #n init#rg to MA+E-INSTANCE 6ill !et the ?#lue, #''ecting #ll in!t#nce! o' the cl#!!. 7ec#u!e you c#n@t get #t # cl#!!-#lloc#ted !lot 6ithout #n in!t#nce o' the cl#!!, cl#!!-#lloc#ted !lot! #ren@t re#lly eFui?#lent to static or class 'ield! in l#ngu#ge! !uch #! D#?#, CEE, #nd Python.11 $#ther, cl#!!-#lloc#ted !lot! #re u!ed pri*#rily to !#?e !p#ceG i' you@re going to cre#te *#ny in!t#nce! o' # cl#!! #nd #ll in!t#nce! #re going to h#?e # re'erence to the !#*e ob<ect--!#y, # pool o' !h#red re!ource!--you c#n !#?e the co!t o' e#ch in!t#nce h#?ing it! o6n re'erence by *#9ing the !lot cl#!!-#lloc#ted.
de'#ult ?#lue, i' *ultiple cl#!!e! !peci'y #n :init(orm, the ne6 cl#!! u!e! the one 'ro* the *o!t !peci'ic cl#!!. &hi! #llo6! # !ubcl#!! to !peci'y # di''erent de'#ult ?#lue th#n the one it 6ould other6i!e inherit. 5n the other h#nd, :initarg! needn@t be e.clu!i?e--e#ch :initarg option in # !lot !peci'ier cre#te! # 9ey6ord p#r#*eter th#t c#n be u!ed to initi#liAe the !lotG *ultiple p#r#*eter! don@t cre#te # con'lict, !o the ne6 !lot !peci'ier cont#in! #ll the :initarg!. C#ller! o' MA+E-INSTANCE c#n u!e #ny o' the :initarg! to initi#liAe the !lot. I' # c#ller p#!!e! *ultiple 9ey6ord #rgu*ent! th#t initi#liAe the !#*e !lot, then the le't*o!t #rgu*ent in the c#ll to MA+E-INSTANCE i! u!ed. Inherited :reader, :writer, #nd :accessor option! #ren@t included in the *erged !lot !peci'ier !ince the *ethod! cre#ted by the !upercl#!!@! DEFCLASS 6ill #lre#dy #pply to the ne6 cl#!!. &he ne6 cl#!! c#n, ho6e?er, cre#te it! o6n #cce!!or 'unction! by !upplying it! o6n :reader, :writer, or :accessor option!. /in#lly, the :allocation option i!, li9e :init(orm, deter*ined by the *o!t !peci'ic cl#!! th#t !peci'ie! the !lot. &hu!, it@! po!!ible 'or #ll in!t#nce! o' one cl#!! to !h#re # :class !lot 6hile in!t#nce! o' # !ubcl#!! *#y e#ch h#?e their o6n :instance !lot o' the !#*e n#*e. %nd # !ub!ubcl#!! *#y then rede'ine it b#c9 to :class !lot, !o #ll in!t#nce! o' that cl#!! 6ill #g#in !h#re # !ingle !lot. In the l#tter c#!e, the !lot !h#red by in!t#nce! o' the !ub-!ubcl#!! i! di''erent th#n the !lot !h#red by the origin#l !upercl#!!. /or in!t#nce, !uppo!e you h#?e the!e cl#!!e!:
1de(class#(oo#13 ##11a#:initarg#:a#:init(orm#4I4#:accessor#a3 ###1b#:initarg#:b#:init(orm#4L4#:accessor#b333 1de(class#bar#1(oo3 ##11a#:init(orm#1error#4%'st#s'ppl?#a#val'e#(or#a433 ###1b#:initarg#:the-b#:accessor#the-b#:allocation#:class333
When in!t#nti#ting the cl#!! bar, you c#n u!e the inherited init#rg, :a, to !peci'y # ?#lue 'or the !lot a# #nd, in '#ct, *u!t do !o to #?oid #n error, !ince the :init(orm !upplied by bar !uper!ede! the one inherited 'ro* (oo. &o initi#liAe the b !lot, you c#n u!e either the inherited init#rg :b or the ne6 init#rg :the-b. >o6e?er, bec#u!e o' the :allocation option on the b !lot in bar, the ?#lue !peci'ied 6ill be !tored in the !lot !h#red by #ll in!t#nce! o' bar. &h#t !#*e !lot c#n be #cce!!ed either 6ith the *ethod on the generic 'unction b th#t !peci#liAe! on (oo or 6ith the ne6 *ethod on the generic 'unction the-b th#t !peci#liAe! directly on bar. &o #cce!! the a !lot on either # (oo or # bar, you@ll continue to u!e the generic 'unction a. 8!u#lly *erging !lot de'inition! 6or9! Fuite nicely. >o6e?er, it@! i*port#nt to be #6#re 6hen u!ing *ultiple inherit#nce th#t t6o unrel#ted !lot! th#t h#ppen to h#?e the !#*e n#*e c#n be *erged into # !ingle !lot in the ne6 cl#!!. &hu!, *ethod! !peci#liAed on di''erent cl#!!e! could end up *#nipul#ting the !#*e !lot 6hen #pplied to # cl#!! th#t e.tend! tho!e cl#!!e!. &hi! i!n@t *uch o' # proble* in pr#ctice !ince, #! you@ll !ee in Ch#pter 21, you c#n u!e the p#c9#ge !y!te* to #?oid colli!ion! bet6een n#*e! in independently de?eloped piece! o' code.
+u%tip%e Inheritance
%ll the cl#!!e! you@?e !een !o '#r h#?e h#d only # !ingle direct !upercl#!!. Co**on i!p #l!o !upport! *ultiple inherit#nce--# cl#!! c#n h#?e *ultiple direct !upercl#!!e!, inheriting #pplic#ble *ethod! #nd !lot !peci'ier! 'ro* #ll o' the*.
3ultiple inherit#nce doe!n@t dr#*#tic#lly ch#nge #ny o' the *ech#ni!*! o' inherit#nce I@?e di!cu!!ed !o '#r--e?ery u!er-de'ined cl#!! #lre#dy h#! *ultiple !upercl#!!e! !ince they #ll e.tend STANDARDOB4ECT, 6hich e.tend! T, #nd !o h#?e #t le#!t t6o !upercl#!!e!. &he 6rin9le th#t *ultiple inherit#nce #dd! i! th#t # cl#!! c#n h#?e *ore th#n one direct !upercl#!!. &hi! co*plic#te! the notion o' cl#!! !peci'icity th#t@! u!ed both 6hen building the e''ecti?e *ethod! 'or # generic 'unction #nd 6hen *erging inherited !lot !peci'ier!. &h#t i!, i' cl#!!e! could h#?e only # !ingle direct !upercl#!!, ordering cl#!!e! by !peci'icity 6ould be tri?i#l--# cl#!! #nd #ll it! !upercl#!!e! could be ordered in # !tr#ight line !t#rting 'ro* the cl#!! it!el', 'ollo6ed by it! !ingle direct !upercl#!!, 'ollo6ed by its direct !upercl#!!, #ll the 6#y up to T. 7ut 6hen # cl#!! h#! *ultiple direct !upercl#!!e!, tho!e !upercl#!!e! #re typic#lly not rel#ted to e#ch other-indeed, i' one 6#! # !ubcl#!! o' #nother, you 6ouldn@t need to !ubcl#!! both directly. In th#t c#!e, the rule th#t !ubcl#!!e! #re *ore !peci'ic th#n their !upercl#!!e! i!n@t enough to order #ll the !upercl#!!e!. So Co**on i!p u!e! # !econd rule th#t !ort! unrel#ted !upercl#!!e! #ccording to the order they@re li!ted in the DEFCLASS@! direct !upercl#!! li!t--cl#!!e! e#rlier in the li!t #re con!idered *ore !peci'ic th#n cl#!!e! l#ter in the li!t. &hi! rule i! #d*ittedly !o*e6h#t #rbitr#ry but doe! #llo6 e?ery cl#!! to h#?e # line#r class precedence list, 6hich c#n be u!ed to deter*ine 6hich !upercl#!!e! !hould be con!idered *ore !peci'ic th#n other!. :ote, ho6e?er, there@! no glob#l ordering o' cl#!!e!--e#ch cl#!! h#! it! o6n cl#!! precedence li!t, #nd the !#*e cl#!!e! c#n #ppe#r in di''erent order! in di''erent cl#!!e!@ cl#!! precedence li!t!. &o !ee ho6 thi! 6or9!, let@! #dd # cl#!! to the b#n9ing #pp: mone?-mar&et-acco'nt. % *oney *#r9et #ccount co*bine! the ch#r#cteri!tic! o' # chec9ing #ccount #nd # !#?ing! #ccount: # cu!to*er c#n 6rite chec9! #g#in!t it, but it #l!o e#rn! intere!t. 4ou *ight de'ine it li9e thi!:
1de(class#mone?-mar&et-acco'nt#1chec&ing-acco'nt#savings-acco'nt3#133
:ote ho6 thi! li!t !#ti!'ie! both rule!: e?ery cl#!! #ppe#r! be'ore #ll it! !upercl#!!e!, #nd chec&ingacco'nt #nd savings-acco'nt #ppe#r in the order !peci'ied in DEFCLASS. &hi! cl#!! de'ine! no !lot! o' it! o6n but 6ill inherit !lot! 'ro* both o' it! direct !upercl#!!e!, including the !lot! they inherit 'ro* their !upercl#!!e!. i9e6i!e, #ny *ethod th#t@! #pplic#ble to #ny cl#!! in the cl#!! precedence li!t 6ill be #pplic#ble to # mone?-mar&et-acco'nt ob<ect. 7ec#u!e #ll !lot !peci'ier! 'or the !#*e !lot #re *erged, it doe!n@t *#tter th#t mone?-mar&et-acco'nt inherit! the !#*e !lot !peci'ier! 'ro* ban&-acco'nt t6ice. 12 3ultiple inherit#nce i! e#!ie!t to under!t#nd 6hen the di''erent !upercl#!!e! pro?ide co*pletely independent !lot! #nd beh#?ior!. /or in!t#nce, mone?-mar&et-acco'nt 6ill inherit !lot! #nd beh#?ior! 'or de#ling 6ith chec9! 'ro* chec&ing-acco'nt #nd !lot! #nd beh#?ior! 'or co*puting intere!t 'ro* savings-acco'nt. 4ou don@t h#?e to 6orry #bout the cl#!! precedence li!t 'or *ethod! #nd !lot! inherited 'ro* only one !upercl#!! or #nother. >o6e?er, it@! #l!o po!!ible to inherit di''erent *ethod! 'or the !#*e generic 'unction 'ro* di''erent !upercl#!!e!. In th#t c#!e, the cl#!! precedence li!t doe! co*e into pl#y. /or in!t#nce, !uppo!e the
b#n9ing #pplic#tion de'ined # generic 'unction print-statement u!ed to gener#te *onthly !t#te*ent!. Pre!u*#bly there 6ould #lre#dy be *ethod! 'or print-statement !peci#liAed on both chec&ing-acco'nt #nd savings-acco'nt. 7oth o' the!e *ethod! 6ill be #pplic#ble to in!t#nce! o' mone?-mar&et-acco'nt, but the one !peci#liAed on chec&ing-acco'nt 6ill be con!idered *ore !peci'ic th#n the one on savings-acco'nt bec#u!e chec&ing-acco'nt precede! savings-acco'nt in mone?-mar&et-acco'nt@! cl#!! precedence li!t. %!!u*ing the inherited *ethod! #re #ll pri*#ry *ethod! #nd you h#?en@t de'ined #ny other *ethod!, the *ethod !peci#liAed on chec&ing-acco'nt 6ill be u!ed i' you in?o9e print-statement on mone?-mar&et-acco'nt. >o6e?er, th#t 6on@t nece!!#rily gi?e you the beh#?ior you 6#nt !ince you prob#bly 6#nt # *oney *#r9et #ccount@! !t#te*ent to cont#in ele*ent! o' both # chec9ing #ccount #nd # !#?ing! #ccount !t#te*ent. 4ou c#n *odi'y the beh#?ior o' print-statement 'or mone?-mar&et-acco'nt! in # couple 6#y!. 5ne !tr#ight'or6#rd 6#y i! to de'ine # ne6 pri*#ry *ethod !peci#liAed on mone?-mar&etacco'nt. &hi! gi?e! you the *o!t control o?er the ne6 beh#?ior but 6ill prob#bly reFuire *ore ne6 code th#n !o*e other option! I@ll di!cu!! in # *o*ent. &he proble* i! th#t 6hile you c#n u!e CALLNEXT-METHOD to c#ll HupH to the ne.t *o!t !peci'ic *ethod, n#*ely, the one !peci#liAed on chec&ing-acco'nt, there@! no 6#y to in?o9e # p#rticul#r le!!-!peci'ic *ethod, !uch #! the one !peci#liAed on savings-acco'nt. &hu!, i' you 6#nt to be #ble to reu!e the code th#t print! the savings-acco'nt p#rt o' the !t#te*ent, you@ll need to bre#9 th#t code into # !ep#r#te 'unction, 6hich you c#n then c#ll directly 'ro* both the mone?-mar&et-acco'nt #nd savingsacco'nt print-statement *ethod!. %nother po!!ibility i! to 6rite the pri*#ry *ethod! o' #ll three cl#!!e! to c#ll CALL-NEXT-METHOD. &hen the *ethod !peci#liAed on mone?-mar&et-acco'nt 6ill u!e CALL-NEXT-METHOD to in?o9e the *ethod !peci#liAed on chec&ing-acco'nt. When th#t *ethod c#ll! CALL-NEXTMETHOD, it 6ill re!ult in running the savings-acco'nt *ethod !ince it 6ill be the ne.t *o!t !peci'ic *ethod #ccording to mone?-mar&et-acco'nt@! cl#!! precedence li!t. 5' cour!e, i' you@re going to rely on # coding con?ention--th#t e?ery *ethod c#ll! CALL-NEXTMETHOD--to en!ure #ll the #pplic#ble *ethod! run #t !o*e point, you !hould thin9 #bout u!ing #u.ili#ry *ethod! in!te#d. In thi! c#!e, in!te#d o' de'ining pri*#ry *ethod! on print-statement 'or chec&ing-acco'nt #nd savings-acco'nt, you c#n de'ine tho!e *ethod! #! :a(ter *ethod!, de'ining # !ingle pri*#ry *ethod on ban&-acco'nt. &hen, print-statement, c#lled on # mone?-mar&et-acco'nt, 6ill print # b#!ic #ccount !t#te*ent, output by the pri*#ry *ethod !peci#liAed on ban&-acco'nt, 'ollo6ed by det#il! output by the :a(ter *ethod! !peci#liAed on savings-acco'nt #nd chec&ing-acco'nt. %nd i' you 6#nt to #dd det#il! !peci'ic to mone?mar&et-acco'nt!, you c#n de'ine #n :a(ter *ethod !peci#liAed on mone?-mar&etacco'nt, 6hich 6ill run l#!t o' #ll. &he #d?#nt#ge o' u!ing #u.ili#ry *ethod! i! th#t it *#9e! it Fuite cle#r 6hich *ethod! #re pri*#rily re!pon!ible 'or i*ple*enting the generic 'unction #nd 6hich one! #re only contributing #ddition#l bit! o' 'unction#lity. &he di!#d?#nt#ge i! th#t you don@t get 'ine-gr#ined control o?er the order in 6hich the #u.ili#ry *ethod! run--i' you 6#nted the chec&ing-acco'nt p#rt o' the !t#te*ent to print be'ore the savings-acco'nt p#rt, you@d h#?e to ch#nge the order in 6hich the mone?-mar&etacco'nt !ubcl#!!e! tho!e cl#!!e!. 7ut th#t@! # '#irly dr#*#tic ch#nge th#t could #''ect other *ethod! #nd inherited !lot!. In gener#l, i' you 'ind your!el' t6iddling the order o' the direct !upercl#!! li!t #! # 6#y o' 'ine-tuning the beh#?ior o' !peci'ic *ethod!, you prob#bly need to !tep b#c9 #nd rethin9 your #ppro#ch.
5n the other h#nd, i' you don@t c#re e.#ctly 6h#t the order i! but 6#nt it to be con!i!tent #cro!! !e?er#l generic 'unction!, then u!ing #u.ili#ry *ethod! *#y be <u!t the thing. /or e.#*ple, i' in #ddition to print-statement you h#?e # print-detailed-statement generic 'unction, you c#n i*ple*ent both 'unction! u!ing :a(ter *ethod! on the ?#riou! !ubcl#!!e! o' ban&-acco'nt, #nd the order o' the p#rt! o' both # regul#r #nd # det#iled !t#te*ent 6ill be the !#*e.
ne6 *ethod! 'or #n e.i!ting cl#!! *#y !ee* !tr#nge to 'ol9! u!ed to !t#tic#lly typed l#ngu#ge! !uch #! CEE #nd D#?# in 6hich #ll the *ethod! o' # cl#!! *u!t be de'ined #! p#rt o' the cl#!! de'inition. 7ut progr#**er! 6ith e.perience in dyn#*ic#lly typed ob<ect-oriented l#ngu#ge! !uch #! S*#llt#l9 #nd 5b<ecti?e C 6ill 'ind nothing !tr#nge #bout #dding ne6 beh#?ior! to e.i!ting cl#!!e!.
2In
other ob<ect-oriented l#ngu#ge!, !lot! *ight be c#lled fields, member variables, or attributes.
3%!
6hen n#*ing 'unction! #nd ?#ri#ble!, it@! not Fuite true th#t you c#n u!e an0 !y*bol #! # cl#!! n#*e--you c#n@t u!e n#*e! de'ined by the l#ngu#ge !t#nd#rd. 4ou@ll !ee in Ch#pter 21 ho6 to #?oid !uch n#*e con'lict!.
-&he
#rgu*ent to MA+E-INSTANCE c#n #ctu#lly be either the n#*e o' the cl#!! or # cl#!! ob<ect returned by the 'unction CLASS-OF or FIND-CLASS.
5%nother
6#y to #''ect the ?#lue! o' !lot! i! 6ith the :de(a'lt-initargs option to DEFCLASS. &hi! option i! u!ed to !peci'y 'or*! th#t 6ill be e?#lu#ted to pro?ide #rgu*ent! 'or !peci'ic initi#liA#tion p#r#*eter! th#t #ren@t gi?en # ?#lue in # p#rticul#r c#ll to MA+E-INSTANCE. 4ou don@t need to 6orry #bout :de(a'lt-initargs 'or no6.
0%dding 25ne
#n :a(ter *ethod to INITIALI3E-INSTANCE i! the Co**on i!p #n#log to de'ining # con!tructor in D#?# or CEE or #n ==init== *ethod in Python. *i!t#9e you *ight *#9e until you get u!ed to u!ing #u.ili#ry *ethod! i! to de'ine # *ethod on INITIALI3E-INSTANCE but 6ithout the :a(ter Fu#li'ier. I' you do th#t, you@ll get # ne6 pri*#ry *ethod th#t !h#do6! the de'#ult one. 4ou c#n re*o?e the un6#nted pri*#ry *ethod u!ing the 'unction! REMOVE-METHOD #nd FIND-METHOD. Cert#in de?elop*ent en?iron*ent! *#y pro?ide # gr#phic#l u!er inter'#ce to do the !#*e thing.
1remove-method#NCinitiali*e-instance ##1(ind-method#NCinitiali*e-instance#13#1list#1(ind-class#Cban&-acco'nt3333
5' cour!e, pro?iding #n #cce!!or 'unction doe!n@t re#lly li*it #nything !ince other code c#n !till u!e SLOT-VALUE to get #t !lot! directly. Co**on i!p doe!n@t pro?ide !trict enc#p!ul#tion o' !lot! the 6#y !o*e l#ngu#ge! !uch #! CEE #nd D#?# doG ho6e?er, i' the #uthor o' # cl#!! pro?ide! #cce!!or 'unction! #nd you ignore the*, u!ing SLOT-VALUE in!te#d, you h#d better 9no6 6h#t you@re doing. It@! #l!o po!!ible to u!e the p#c9#ge !y!te*, 6hich I@ll di!cu!! in Ch#pter 21, to *#9e it e?en *ore ob?iou! th#t cert#in !lot! #ren@t to be #cce!!ed directly, by not e.porting the n#*e! o' the !lot!.
)5ne
con!eFuence o' de'ining # SETF 'unction--!#y, 1set(#(oo3--i! th#t i' you #l!o de'ine the corre!ponding #cce!!or 'unction, (oo in thi! c#!e, you c#n u!e #ll the *odi'y *#cro! built upon SETF, !uch #! INCF, DECF, PUSH, #nd POP, on the ne6 9ind o' pl#ce.
10&he
H?#ri#bleH n#*e! pro?ided by WITH-SLOTS #nd WITH-ACCESSORS #ren@t true ?#ri#ble!G they@re i*ple*ented u!ing # !peci#l 9ind o' *#cro, c#lled # s0mbol macro, th#t #llo6! # !i*ple n#*e to e.p#nd into #rbitr#ry code. Sy*bol *#cro! 6ere introduced into the l#ngu#ge to !upport WITHSLOTS #nd WITH-ACCESSORS, but you c#n #l!o u!e the* 'or your o6n purpo!e!. I@ll di!cu!! the* in # bit *ore det#il in Ch#pter 20.
11&he
3et# 5b<ect Protocol B35PC, 6hich i!n@t p#rt o' the l#ngu#ge !t#nd#rd but i! !upported by *o!t Co**on i!p i*ple*ent#tion!, pro?ide! # 'unction, class-protot?pe, th#t return! #n in!t#nce o' # cl#!! th#t c#n be u!ed to #cce!! cl#!! !lot!. I' you@re u!ing #n i*ple*ent#tion th#t !upport! the 35P #nd h#ppen to be tr#n!l#ting !o*e code 'ro* #nother l#ngu#ge th#t *#9e! he#?y u!e o' !t#tic or cl#!! 'ield!, thi! *#y gi?e you # 6#y to e#!e the tr#n!l#tion. 7ut it@! not #ll th#t idio*#tic.
12In
other 6ord!, Co**on i!p doe!n@t !u''er 'ro* the diamond inheritance proble* the 6#y, !#y, CE E doe!. In CEE, 6hen one cl#!! !ubcl#!!e! t6o cl#!!e! th#t both inherit # *e*ber ?#ri#ble 'ro* # co**on !upercl#!!, the botto* cl#!! inherit! the *e*ber ?#ri#ble t6ice, le#ding to no end o' con'u!ion.
&h#t@! not too b#d, but #nyone re#ding thi! code h#! to *ent#lly p#r!e it <u!t to 'igure out th#t #ll it@! doing i! printing the content! o' list to !t#nd#rd output. 5n the other h#nd, you c#n tell #t # gl#nce th#t the 'ollo6ing e.pre!!ion i! printing list, in !o*e 'or*, to !t#nd#rd output:
1(ormat#t#47V7a7`5#7W4#list3
I' you c#re e.#ctly 6h#t 'or* the output 6ill t#9e, then you@ll h#?e to e.#*ine the control !tring, but i' #ll you 6#nt i! # 'ir!t-order #ppro.i*#tion o' 6h#t thi! line o' code i! doing, th#t@! i**edi#tely #?#il#ble. %t #ny r#te, you !hould h#?e #t le#!t # re#ding 9no6ledge o' FORMAT, #nd it@! 6orth getting # !en!e o' 6h#t it c#n do be'ore you #''ili#te your!el' 6ith the pro- or #nti-FORMAT c#*p. It@! #l!o i*port#nt to under!t#nd #t le#!t the b#!ic! o' FORMAT bec#u!e other !t#nd#rd 'unction!, !uch #! the condition!ign#ling 'unction! di!cu!!ed in the ne.t ch#pter, u!e FORMAT-!tyle control !tring! to gener#te output. &o 'urther co*plic#te *#tter!, FORMAT !upport! three Fuite di''erent 9ind! o' 'or*#tting: printing t#ble! o' d#t#, prett0)printing !-e.pre!!ion!, #nd gener#ting hu*#n-re#d#ble *e!!#ge! 6ith interpol#ted ?#lue!. Printing t#ble! o' d#t# #! te.t i! # bit p#!!^ the!e d#y!G it@! one o' tho!e re*inder! th#t i!p i! ne#rly #! old #! /5$&$%:. In '#ct, !e?er#l o' the directi?e! you c#n u!e to print 'lo#ting-point ?#lue! in 'i.ed-6idth 'ield! 6ere b#!ed Fuite directly on /5$&$%: edit descriptors, 6hich #re u!ed in /5$&$%: to re#d #nd print colu*n! o' d#t# #rr#nged in 'i.ed-6idth 'ield!. >o6e?er, u!ing Co**on i!p #! # /5$&$%: repl#ce*ent i! beyond the !cope o' thi! boo9, !o I 6on@t di!cu!! tho!e #!pect! o' FORMAT. Pretty-printing i! li9e6i!e beyond the !cope o' thi! boo9--not bec#u!e it@! p#!!^ but <u!t bec#u!e it@! too big # topic. 7rie'ly, the Co**on i!p pretty printer i! # cu!to*iA#ble !y!te* 'or printing bloc9!tructured d#t# !uch #!--but not li*ited to--!-e.pre!!ion! 6hile ?#rying indent#tion #nd dyn#*ic#lly #dding line bre#9! #! needed. It@! # gre#t thing 6hen you need it, but it@! not o'ten needed in d#y-to-d#y progr#**ing.2 In!te#d, I@ll 'ocu! on the p#rt! o' FORMAT you c#n u!e to gener#te hu*#n-re#d#ble !tring! 6ith interpol#ted ?#lue!. (?en li*iting the !cope in th#t 6#y, there@! !till # '#ir bit to co?er. 4ou !houldn@t 'eel obliged to re*e*ber e?ery det#il de!cribed in thi! ch#pter. 4ou c#n get Fuite '#r 6ith <u!t # 'e6 FORMAT idio*!. I@ll de!cribe the *o!t i*port#nt 'e#ture! o' FORMAT 'ir!tG it@! up to you ho6 *uch o' # FORMAT 6iA#rd you 6#nt to beco*e.
opti*iAed 'or co*p#ctne!! r#ther th#n e#!y co*prehen!ion. &hi! i! 6hy # co*ple. FORMAT control !tring c#n end up loo9ing li9e line noi!e. 3o!t o' FORMAT@! directi?e! !i*ply interpol#te #n #rgu*ent into the output in one 'or* or #nother. So*e directi?e!, !uch #! 76, 6hich c#u!e! FORMAT to e*it # ne6line, don@t con!u*e #ny #rgu*ent!. %nd other!, #! you@ll !ee, c#n con!u*e *ore th#n one #rgu*ent. 5ne directi?e e?en #llo6! you to <u*p #round in the li!t o' #rgu*ent! in order to proce!! the !#*e #rgu*ent *ore th#n once or to !9ip cert#in #rgu*ent! in cert#in !itu#tion!. 7ut be'ore I di!cu!! !peci'ic directi?e!, let@! loo9 #t the gener#l !ynt#. o' # directi?e.
F7R+AT 1irecti,es
%ll directi?e! !t#rt 6ith # tilde B7C #nd end 6ith # !ingle ch#r#cter th#t identi'ie! the directi?e. 4ou c#n 6rite the ch#r#cter in either upper- or lo6erc#!e. So*e directi?e! t#9e prefi3 parameters, 6hich #re 6ritten i**edi#tely 'ollo6ing the tilde, !ep#r#ted by co**#!, #nd u!ed to control thing! !uch #! ho6 *#ny digit! to print #'ter the deci*#l point 6hen printing # 'lo#ting-point nu*ber. /or e.#*ple, the 7\# directi?e, one o' the directi?e! u!ed to print 'lo#ting-point ?#lue!, by de'#ult print! t6o digit! 'ollo6ing the deci*#l point.
$L-+,-./#1(ormat#t#47\4#pi3 3.04 89L
>o6e?er, 6ith # pre'i. p#r#*eter, you c#n !peci'y th#t it !hould print it! #rgu*ent to, !#y, 'i?e deci*#l pl#ce! li9e thi!:
$L-+,-./#1(ormat#t#47"\4#pi3 3.040"9 89L
&he ?#lue! o' pre'i. p#r#*eter! #re either nu*ber!, 6ritten in deci*#l, or ch#r#cter!, 6ritten #! # !ingle Fuote 'ollo6ed by the de!ired ch#r#cter. &he ?#lue o' # pre'i. p#r#*eter c#n #l!o be deri?ed 'ro* the 'or*#t #rgu*ent! in t6o 6#y!: % pre'i. p#r#*eter o' v c#u!e! FORMAT to con!u*e one 'or*#t #rgu*ent #nd u!e it! ?#lue 'or the pre'i. p#r#*eter. %nd # pre'i. p#r#*eter o' N 6ill be e?#lu#ted #! the nu*ber o' re*#ining 'or*#t #rgu*ent!. /or e.#*ple:
$L-+,-./#1(ormat#t#47v\4#3#pi3 3.04! 89L $L-+,-./#1(ormat#t#47N\4#pi3 3.0 89L
I@ll gi?e !o*e *ore re#li!tic e.#*ple! o' ho6 you c#n u!e the N #rgu*ent in the !ection HCondition#l /or*#tting.H 4ou c#n #l!o o*it pre'i. p#r#*eter! #ltogether. >o6e?er, i' you 6#nt to !peci'y one p#r#*eter but not the one! be'ore it, you *u!t include # co**# 'or e#ch un!peci'ied p#r#*eter. /or in!t#nce, the 7E directi?e, #nother directi?e 'or printing 'lo#ting-point ?#lue!, #l!o t#9e! # p#r#*eter to control the nu*ber o' deci*#l pl#ce! to print, but it@! the !econd p#r#*eter r#ther th#n the 'ir!t. I' you 6#nt to u!e 7E to print # nu*ber to 'i?e deci*#l pl#ce!, you c#n 6rite thi!:
$L-+,-./#1(ormat#t#475"(4#pi3 3.040"9
89L
4ou c#n #l!o *odi'y the beh#?ior o' !o*e directi?e! 6ith colon #nd #t-!ign modifiers, 6hich #re pl#ced #'ter #ny pre'i. p#r#*eter! #nd be'ore the directi?e@! identi'ying ch#r#cter. &he!e *odi'ier! ch#nge the beh#?ior o' the directi?e in !*#ll 6#y!. /or in!t#nce, 6ith # colon *odi'ier, the 7< directi?e u!ed to output integer! in deci*#l e*it! the nu*ber 6ith co**#! !ep#r#ting e?ery three digit!, 6hile the #t!ign *odi'ier c#u!e! 7< to include # plu! !ign 6hen the nu*ber i! po!iti?e.
$L-+,-./#1(ormat#t#47d4#0 0 89L $L-+,-./#1(ormat#t#47:d4#0 05 5 89L $L-+,-./#1(ormat#t#47Pd4#0 20 89L 3 3 3
When it *#9e! !en!e, you c#n co*bine the colon #nd #t-!ign *odi'ier! to get both *odi'ic#tion!.
$L-+,-./#1(ormat#t#47:Pd4#0 205 5 89L 3
In directi?e! 6here the t6o *odi'ied beh#?ior! c#n@t be *e#ning'ully co*bined, u!ing both *odi'ier! i! either unde'ined or gi?en # third *e#ning.
Basic For$atting
:o6 you@re re#dy to loo9 #t !peci'ic directi?e!. I@ll !t#rt 6ith !e?er#l o' the *o!t co**only u!ed directi?e!, including !o*e you@?e !een in pre?iou! ch#pter!. &he *o!t gener#l-purpo!e directi?e i! 7I, 6hich con!u*e! one 'or*#t #rgu*ent o' #ny type #nd output! it in aesthetic Bhu*#n-re#d#bleC 'or*. /or e.#*ple, !tring! #re output 6ithout Fuot#tion *#r9! or e!c#pe ch#r#cter!, #nd nu*ber! #re output in # n#tur#l 6#y 'or the type o' nu*ber. I' you <u!t 6#nt to e*it # ?#lue 'or hu*#n con!u*ption, thi! directi?e i! your be!t bet.
1(ormat#nil#4Fhe#val'e#is:#7a4#0 3###########==/#4Fhe#val'e#is:#0 4 1(ormat#nil#4Fhe#val'e#is:#7a4#4(oo43########==/#4Fhe#val'e#is:#(oo4 1(ormat#nil#4Fhe#val'e#is:#7a4#1list#0#!#333#==/#4Fhe#val'e#is:#10#!#334
% clo!ely rel#ted directi?e, 7,, li9e6i!e con!u*e! one 'or*#t #rgu*ent o' #ny type #nd output! it. >o6e?er, 7, trie! to gener#te output th#t c#n be re#d b#c9 in 6ith READ. &hu!, !tring! 6ill be enclo!ed in Fuot#tion *#r9!, !y*bol! 6ill be p#c9#ge-Fu#li'ied 6hen nece!!#ry, #nd !o on. 5b<ect! th#t don@t h#?e # READ#ble repre!ent#tion #re printed 6ith the unre#d#ble ob<ect !ynt#., NO/. With # colon *odi'ier, both the 7I #nd 7, directi?e! e*it NIL #! 13 r#ther th#n NIL. 7oth the 7I #nd 7, directi?e! #l!o t#9e up to 'our pre'i. p#r#*eter!, 6hich c#n be u!ed to control 6hether p#dding i! #dded #'ter Bor be'ore 6ith the #t-!ign *odi'ierC the ?#lue, but tho!e p#r#*eter! #re only re#lly u!e'ul 'or gener#ting t#bul#r d#t#. &he other t6o *o!t 'reFuently u!ed directi?e! #re 76, 6hich e*it! # ne6line, #nd 7>, 6hich e*it! # fresh line. &he di''erence bet6een the t6o i! th#t 76 #l6#y! e*it! # ne6line, 6hile 7> e*it! one only i' it@! not #lre#dy #t the beginning o' # line. &hi! i! h#ndy 6hen 6riting loo!ely coupled 'unction! th#t
e#ch gener#te # piece o' output #nd th#t need to be co*bined in di''erent 6#y!. /or in!t#nce, i' one 'unction gener#te! output th#t end! 6ith # ne6line B76C #nd #nother 'unction gener#te! !o*e output th#t !t#rt! 6ith # 're!h line B7>C, you don@t h#?e to 6orry #bout getting #n e.tr# bl#n9 line i' you c#ll the* one #'ter the other. 7oth o' the!e directi?e! c#n t#9e # !ingle pre'i. p#r#*eter th#t !peci'ie! the nu*ber o' ne6line! to e*it. &he 76 directi?e 6ill !i*ply e*it th#t *#ny ne6line ch#r#cter!, 6hile the 7> directi?e 6ill e*it either n - 1 or n ne6line!, depending on 6hether it !t#rt! #t the beginning o' # line. e!! 'reFuently u!ed i! the rel#ted 77 directi?e, 6hich c#u!e! FORMAT to e*it # liter#l tilde. i9e the 7 6 #nd 7> directi?e!, it c#n be p#r#*eteriAed 6ith # nu*ber th#t control! ho6 *#ny tilde! to e*it.
With the #t-!ign *odi'ier, 7P$ 6ill e*it the ch#r#cter in i!p@! liter#l ch#r#cter !ynt#..
$L-+,-./#1(ormat#t#47Pc764#NYa3 NYa 89L
With both the colon #nd #t-!ign *odi'ier!, the 7$ directi?e c#n print e.tr# in'or*#tion #bout ho6 to enter the ch#r#cter #t the 9eybo#rd i' it reFuire! !peci#l 9ey co*bin#tion!. /or in!t#nce, on the 3#cinto!h, in cert#in #pplic#tion! you c#n enter # null ch#r#cter Bch#r#cter code 0 in %SCII or in #ny %SCII !uper!et !uch #! IS5-,,5)-1 or 8nicodeC by pre!!ing the Control 9ey #nd typing W. In 5pen3C , i' you print the null ch#r#cter 6ith the 7:$ directi?e, it tell! you thi!:
1(ormat#nil#47:Pc4#1code-char# 33#==/#4`P#1$ontrol#P34
>o6e?er, not #ll i!p! i*ple*ent thi! #!pect o' the 7$ directi?e. %nd e?en i' they do, it *#y or *#y not be #ccur#te--'or in!t#nce, i' you@re running 5pen3C in S I3(, the $-P 9ey chord i! intercepted by (*#c!, in?o9ing set-mar&-command./or*#t directi?e! dedic#ted to e*itting nu*ber! #re #nother i*port#nt c#tegory. While you c#n u!e the 7I #nd 7, directi?e! to e*it nu*ber!, i' you 6#nt 'ine control o?er ho6 they@re printed, you need to u!e one o' the nu*ber-!peci'ic directi?e!. &he nu*eric directi?e! c#n be di?ided into t6o !ubc#tegorie!: directi?e! 'or 'or*#tting integer ?#lue! #nd directi?e! 'or 'or*#tting 'lo#ting-point
?#lue!. /i?e clo!ely rel#ted directi?e! 'or*#t integer ?#lue!: 7<, 7[, 7;, 7L, #nd 7.. &he *o!t 'reFuently u!ed i! the 7< directi?e, 6hich output! integer! in b#!e 10.
1(ormat#nil#47d4#0 3#==/#40 4
&he 'ir!t pre'i. p#r#*eter c#n !peci'y # *ini*u* 6idth 'or the output, #nd the !econd p#r#*eter c#n !peci'y # p#dding ch#r#cter to u!e. &he de'#ult p#dding ch#r#cter i! !p#ce, #nd p#dding i! #l6#y! in!erted be'ore the nu*ber it!el'.
1(ormat#nil#470!d4#0 1(ormat#nil#470!5C d4#0 3####==/#4#####0 3#==/#4 0 4 4
&he!e p#r#*eter! #re h#ndy 'or 'or*#tting thing! !uch #! d#te! in # 'i.ed-6idth 'or*#t.
1(ormat#nil#4745C d-7!5C d-7!5C d4#! "#6#0 3#==/#4! "- 6-0 4
&he third #nd 'ourth p#r#*eter! #re u!ed in con<unction 6ith the colon *odi'ier: the third p#r#*eter !peci'ie! the ch#r#cter to u!e #! the !ep#r#tor bet6een group! #nd digit!, #nd the 'ourth p#r#*eter !peci'ie! the nu*ber o' digit! per group. &he!e p#r#*eter! de'#ult to # co**# #nd the nu*ber 3. &hu!, you c#n u!e the directi?e 7:< 6ithout p#r#*eter! to output l#rge integer! in !t#nd#rd 'or*#t 'or the 8nited St#te! but c#n ch#nge the co**# to # period #nd the grouping 'ro* 3 to - 6ith 755C.54<.
1(ormat#nil#47:d4#0 1(ormat#nil#4755C.54:d4#0 3#######==/#40 5 3#==/#40. 5 . 4 4
:ote th#t you *u!t u!e co**#! to hold the pl#ce! o' the un!peci'ied 6idth #nd p#dding ch#r#cter p#r#*eter!, #llo6ing the* to 9eep their de'#ult ?#lue!. &he 7[, 7;, #nd 7L directi?e! 6or9 <u!t li9e the 7< directi?e e.cept they e*it nu*ber! in he.#deci*#l Bb#!e 10C, oct#l Bb#!e ,C, #nd bin#ry Bb#!e 2C.
1(ormat#nil#47)4#0 1(ormat#nil#47o4#0 1(ormat#nil#47b4#0 3#==/#4(4!4 4 3#==/#436400 4 3#==/#40000 0 0 0 4
/in#lly, the 7. directi?e i! the gener#l radi3 directi?e. It! 'ir!t p#r#*eter i! # nu*ber bet6een 2 #nd 30 Binclu!i?eC th#t indic#te! 6h#t b#!e to u!e. &he re*#ining p#r#*eter! #re the !#*e #! the 'our p#r#*eter! #ccepted by the 7<, 7[, 7;, #nd 7L directi?e!, #nd the colon #nd #t-!ign *odi'ier! *odi'y it! beh#?ior in the !#*e 6#y. &he 7. directi?e #l!o h#! !o*e !peci#l beh#?ior 6hen u!ed 6ith no pre'i. p#r#*eter!, 6hich I@ll di!cu!! in the !ection H(ngli!h- #ngu#ge +irecti?e!.H
F%oating4"oint 1irecti,es
/our directi?e! 'or*#t 'lo#ting-point ?#lue!: 7E, 7-, 7J, #nd 7\. &he 'ir!t three o' the!e #re the directi?e! b#!ed on /5$&$%:@! edit de!criptor!. I@ll !9ip *o!t o' the det#il! o' tho!e directi?e! !ince they *o!tly h#?e to do 6ith 'or*#tting 'lo#ting-point ?#lue! 'or u!e in t#bul#r 'or*. >o6e?er, you c#n u!e the 7E, 7-, #nd 7\ directi?e! to interpol#te 'lo#ting-point ?#lue! into te.t. &he 7J, or general< 'lo#ting-point directi?e, on the other h#nd, co*bine! #!pect! o' the 7E #nd 7- directi?e! in # 6#y th#t only re#lly *#9e! !en!e 'or gener#ting t#bul#r output. &he 7E directi?e e*it! it! #rgu*ent, 6hich !hould be # nu*ber,5 in deci*#l 'or*#t, po!!ibly controlling the nu*ber o' digit! #'ter the deci*#l point. &he 7E directi?e i!, ho6e?er, #llo6ed to u!e co*puteriAed !cienti'ic not#tion i' the nu*ber i! !u''iciently l#rge or !*#ll. &he 7- directi?e, on the other h#nd, #l6#y! e*it! nu*ber! in co*puteriAed !cienti'ic not#tion. 7oth o' the!e directi?e! t#9e # nu*ber o' pre'i. p#r#*eter!, but you need to 6orry only #bout the !econd, 6hich control! the nu*ber o' digit! to print #'ter the deci*#l point.
1(ormat#nil#47(4#pi3###==/#43.040"9!6"3"R9Q93d 4 1(ormat#nil#4754(4#pi3#==/#43.04064 1(ormat#nil#47e4#pi3###==/#43.040"9!6"3"R9Q93d2 4 1(ormat#nil#4754e4#pi3#==/#43.0406d2 4
&he 7\, or *onet#ry, directi?e i! !i*il#r to 7E but # bit !i*pler. %! it! n#*e !ugge!t!, it@! intended 'or e*itting *onet#ry unit!. With no p#r#*eter!, it@! b#!ic#lly eFui?#lent to 75!E. &o *odi'y the nu*ber o' digit! printed #'ter the deci*#l point, you u!e the first p#r#*eter, 6hile the !econd p#r#*eter control! the *ini*u* nu*ber o' digit! to print be'ore the deci*#l point.
1(ormat#nil#47\4#pi3####==/#43.044 1(ormat#nil#47!54\4#pi3#==/#4 3.044
%ll three directi?e!, 7E, 7-, #nd 7\, c#n be *#de to #l6#y! print # !ign, plu! or *inu!, 6ith the #t-!ign *odi'ier.0
!ng%ish4Language 1irecti,es
So*e o' the h#ndie!t FORMAT directi?e! 'or gener#ting hu*#n-re#d#ble *e!!#ge! #re the one! 'or e*itting (ngli!h te.t. &he!e directi?e! #llo6 you to e*it nu*ber! #! (ngli!h 6ord!, to e*it plur#l *#r9er! b#!ed on the ?#lue o' # 'or*#t #rgu*ent, #nd to #pply c#!e con?er!ion! to !ection! o' FORMAT@! output. &he 7. directi?e, 6hich I di!cu!!ed in HCh#r#cter #nd Integer +irecti?e!,H 6hen u!ed 6ith no b#!e !peci'ied, print! nu*ber! #! (ngli!h 6ord! or $o*#n nu*er#l!. When u!ed 6ith no pre'i. p#r#*eter #nd no *odi'ier!, it e*it! the nu*ber in 6ord! #! # c#rdin#l nu*ber.
1(ormat#nil#47r4#0!343#==/#4one#tho'sand#two#h'ndred#thirt?-(o'r4
%nd 6ith #n #t-!ign *odi'ier, it e*it! the nu*ber #! # $o*#n nu*er#lG 6ith both #n #t-!ign #nd # colon, it e*it! Hold-!tyleH $o*#n nu*er#l! in 6hich 'our! #nd nine! #re 6ritten #! IIII #nd 1IIII in!te#d o' I1 #nd IN.
1(ormat#nil#47Pr4#0!343##==/#4%$$[[[9K4 1(ormat#nil#47:Pr4#0!343#==/#4%$$[[[99994
/or nu*ber! too l#rge to be repre!ented in the gi?en 'or*, 7. beh#?e! li9e 7<. &o help you gener#te *e!!#ge! 6ith 6ord! properly plur#liAed, FORMAT pro?ide! the 7T directi?e, 6hich !i*ply e*it! #n s unle!! the corre!ponding #rgu*ent i! 0.
1(ormat#nil#4(ile7p4#03##==/#4(ile4 1(ormat#nil#4(ile7p4#0 3#==/#4(iles4 1(ormat#nil#4(ile7p4# 3##==/#4(iles4
&ypic#lly, ho6e?er, you@ll u!e 7T 6ith the colon *odi'ier, 6hich c#u!e! it to reproce!! the pre?iou! 'or*#t #rgu*ent.
1(ormat#nil#47r#(ile7:p4#03##==/#4one#(ile4 1(ormat#nil#47r#(ile7:p4#0 3#==/#4ten#(iles4 1(ormat#nil#47r#(ile7:p4# 3##==/#4*ero#(iles4
With the #t-!ign *odi'ier, 6hich c#n be co*bined 6ith the colon *odi'ier, 7T e*it! either 0 or ies.
1(ormat#nil#47r#(amil7:Pp4#03##==/#4one#(amil?4 1(ormat#nil#47r#(amil7:Pp4#0 3#==/#4ten#(amilies4 1(ormat#nil#47r#(amil7:Pp4# 3##==/#4*ero#(amilies4
5b?iou!ly, 7T c#n@t !ol?e #ll plur#liA#tion proble*! #nd i! no help 'or gener#ting *e!!#ge! in other l#ngu#ge!, but it@! h#ndy 'or the c#!e! it doe! h#ndle. %nd the 7D directi?e, 6hich I@ll di!cu!! in # *o*ent, gi?e! you # *ore 'le.ible 6#y to condition#liAe p#rt! o' FORMAT@! output. &he l#!t directi?e 'or de#ling 6ith e*itting (ngli!h te.t i! 71, 6hich #llo6! you to control the c#!e o' te.t in the output. (#ch 71 i! p#ired 6ith # 73, #nd #ll the output gener#ted by the portion o' the control !tring bet6een the t6o *#r9er! 6ill be con?erted to #ll lo6erc#!e.
1(ormat#nil#4717a734#4E;;43#==/#4(oo4 1(ormat#nil#4717Pr734#0!43##==/#4c))iv4
4ou c#n *odi'y 71 6ith #n #t !ign to *#9e it c#pit#liAe the 'ir!t 6ord in # !ection o' te.t, 6ith # colon to *#9e it to c#pit#liAe #ll 6ord!, #nd 6ith both *odi'ier! to con?ert #ll te.t to upperc#!e. B% word 'or the purpo!e o' thi! directi?e i! # !eFuence o' #lph#nu*eric ch#r#cter! deli*ited by non#lph#nu*eric ch#r#cter! or the end! o' the te.t.C
1(ormat#nil#4717a734#4t:e#Z'ic&#L.;W8#(o[43###==/#4the#@'ic&#brown#(o)4 1(ormat#nil#47P17a734#4t:e#Z'ic&#L.;W8#(o[43##==/#4Fhe#@'ic&#brown#(o)4 1(ormat#nil#47:17a734#4t:e#Z'ic&#L.;W8#(o[43##==/#4Fhe#Z'ic&#Lrown#Eo)4 1(ormat#nil#47:P17a734#4t:e#Z'ic&#L.;W8#(o[43#==/#4F:-#Z+9$M#L.;W8#E;[4
#onditiona% For$atting
In #ddition to directi?e! th#t interpol#te #rgu*ent! #nd *odi'y other output, FORMAT pro?ide! !e?er#l directi?e! th#t i*ple*ent !i*ple control con!truct! 6ithin the control !tring. 5ne o' the!e, 6hich you u!ed in Ch#pter ), i! the conditional directi?e 7D. &hi! directi?e i! clo!ed by # corre!ponding 7G, #nd in bet6een #re # nu*ber o' cl#u!e! !ep#r#ted by 7S. &he <ob o' the 7D directi?e i! to pic9 one o' the cl#u!e!, 6hich i! then proce!!ed by FORMAT. With no *odi'ier! or p#r#*eter!, the cl#u!e i! !elected by nu*eric inde.G the 7D directi?e con!u*e! # 'or*#t #rgu*ent, 6hich !hould be # nu*ber, #nd t#9e!
the nth BAero-b#!edC cl#u!e 6here 2 i! the ?#lue o' the #rgu*ent.
1(ormat#nil#47Dcero7S'no7Sdos7G4# 3#==/#4cero4 1(ormat#nil#47Dcero7S'no7Sdos7G4#03#==/#4'no4 1(ormat#nil#47Dcero7S'no7Sdos7G4#!3#==/#4dos4
I' the ?#lue o' the #rgu*ent i! gre#ter th#n the nu*ber o' cl#u!e!, nothing i! printed.
1(ormat#nil#47Dcero7S'no7Sdos7G4#33#==/#44
>o6e?er, i' the l#!t cl#u!e !ep#r#tor i! 7:S in!te#d o' 7S, then the l#!t cl#u!e !er?e! #! # de'#ult cl#u!e.
1(ormat#nil#47Dcero7S'no7Sdos7:Sm'cho7G4#33###==/#4m'cho4 1(ormat#nil#47Dcero7S'no7Sdos7:Sm'cho7G4#0 3#==/#4m'cho4
It@! #l!o po!!ible to !peci'y the cl#u!e to be !elected u!ing # pre'i. p#r#*eter. While it@d be !illy to u!e # liter#l ?#lue in the control !tring, rec#ll th#t N u!ed #! # pre'i. p#r#*eter *e#n! the nu*ber o' #rgu*ent! re*#ining to be proce!!ed. &hu!, you c#n de'ine # 'or*#t !tring !uch #! the 'ollo6ing:
1de(parameter#Ulist-etcU ##47ND8;8-7S7a7S7a#and#7a7:S7a5#7a7G7ND7S#and#7a7:S5#7a5#etc7G.43
:ote th#t the control !tring #ctu#lly cont#in! t6o 7D7G directi?e!--both o' 6hich u!e N to !elect the cl#u!e to u!e. &he 'ir!t con!u*e! bet6een Aero #nd t6o #rgu*ent!, 6hile the !econd con!u*e! one *ore, i' #?#il#ble. FORMAT 6ill !ilently ignore #ny #rgu*ent! not con!u*ed 6hile proce!!ing the control !tring. With # colon *odi'ier, the 7D c#n cont#in only t6o cl#u!e!G the directi?e con!u*e! # !ingle #rgu*ent #nd proce!!e! the 'ir!t cl#u!e i' the #rgu*ent i! NIL #nd the !econd cl#u!e i! other6i!e. 4ou u!ed thi! ?#ri#nt o' 7D in Ch#pter ) to gener#te p#!!;'#il *e!!#ge!, li9e thi!:
1(ormat#t#47:DEI9L7Spass7G4#test-res'lt3
:ote th#t either cl#u!e c#n be e*pty, but the directi?e *u!t cont#in # 7S. /in#lly, 6ith #n #t-!ign *odi'ier, the 7D directi?e c#n h#?e only one cl#u!e. &he directi?e con!u*e! one #rgu*ent #nd, i' it@! non-NIL, proce!!e! the cl#u!e #'ter b#c9ing up to *#9e the #rgu*ent #?#il#ble to be con!u*ed #g#in.
1(ormat#nil#47PD)#=#7a#7G7PD?#=#7a7G4#0 #! 3###==/#4)#=#0 #?#=#! 4 1(ormat#nil#47PD)#=#7a#7G7PD?#=#7a7G4#0 #nil3##==/#4)#=#0 #4 1(ormat#nil#47PD)#=#7a#7G7PD?#=#7a7G4#nil#! 3##==/#4?#=#! 4 1(ormat#nil#47PD)#=#7a#7G7PD?#=#7a7G4#nil#nil3#==/#44
Iteration
%nother FORMAT directi?e th#t you@?e !een #lre#dy, in p#!!ing, i! the iter#tion directi?e 7V. &hi! directi?e tell! FORMAT to iter#te o?er the ele*ent! o' # li!t or o?er the i*plicit li!t o' the 'or*#t #rgu*ent!. With no *odi'ier!, 7V con!u*e! one 'or*#t #rgu*ent, 6hich *u!t be # li!t. i9e the 7D directi?e, 6hich i! #l6#y! p#ired 6ith # 7G directi?e, the 7V directi?e i! #l6#y! p#ired 6ith # clo!ing 7T. &he te.t bet6een the t6o *#r9er! i! proce!!ed #! # control !tring, 6hich dr#6! it! #rgu*ent! 'ro* the li!t con!u*ed by the 7V directi?e. FORMAT 6ill repe#tedly proce!! thi! control !tring 'or #! long #! the li!t being iter#ted o?er h#! ele*ent! le't. In the 'ollo6ing e.#*ple, the 7V con!u*e! the !ingle 'or*#t #rgu*ent, the li!t 10#!#33, #nd then proce!!e! the control !tring 47a5#4, repe#ting until #ll the ele*ent! o' the li!t h#?e been con!u*ed.
1(ormat#nil#47V7a5#7W4#1list#0#!#333#==/#405#!5#35#4
>o6e?er, it@! #nnoying th#t in the output the l#!t ele*ent o' the li!t i! 'ollo6ed by # co**# #nd # !p#ce. 4ou c#n 'i. th#t 6ith the 7` directi?eG 6ithin the body o' # 7V directi?e, the 7` c#u!e! the iter#tion to !top i**edi#tely, 6ithout proce!!ing the re!t o' the control !tring, 6hen no ele*ent! re*#in in the li!t. &hu!, to #?oid printing the co**# #nd !p#ce #'ter the l#!t ele*ent o' # li!t, you c#n precede the* 6ith # 7`.
1(ormat#nil#47V7a7`5#7W4#1list#0#!#333#==/#405#!5#34
&he 'ir!t t6o ti*e! through the iter#tion, there #re !till unproce!!ed ele*ent! in the li!t 6hen the 7` i! proce!!ed. &he third ti*e through, ho6e?er, #'ter the 7a directi?e con!u*e! the 3, the 7` 6ill c#u!e FORMAT to bre#9 out o' the iter#tion 6ithout printing the co**# #nd !p#ce. With #n #t-!ign *odi'ier, 7V proce!!e! the re*#ining 'or*#t #rgu*ent! #! # li!t.
1(ormat#nil#47PV7a7`5#7W4#0#!#33#==/#405#!5#34
Within the body o' # 7V...7T, the !peci#l pre'i. p#r#*eter N re'er! to the nu*ber o' ite*! re*#ining to be proce!!ed in the li!t r#ther th#n the nu*ber o' re*#ining 'or*#t #rgu*ent!. 4ou c#n u!e th#t, #long 6ith the 7D directi?e, to print # co**#-!ep#r#ted li!t 6ith #n H#ndH be'ore the l#!t ite* li9e thi!:
1(ormat#nil#47V7a7ND7S5#and#7:S5#7G7W4#1list#0#!#333#==/#405#!5#and#34
>o6e?er, th#t doe!n@t re#lly 6or9 right i' the li!t i! t6o ite*! long bec#u!e it #dd! #n e.tr# co**#.
1(ormat#nil#47V7a7ND7S5#and#7:S5#7G7W4#1list#0#!33#==/#405#and#!4
4ou could 'i. th#t in # bunch o' 6#y!. &he 'ollo6ing t#9e! #d?#nt#ge o' the beh#?ior o' 7PV 6hen ne!ted in!ide #nother 7V or 7PV directi?e--it iter#te! o?er 6h#te?er ite*! re*#in in the li!t being iter#ted o?er by the outer 7V. 4ou c#n co*bine th#t 6ith # 7ND directi?e to *#9e the 'ollo6ing control !tring 'or 'or*#tting li!t! #ccording to (ngli!h gr#**#r:
1de(parameter#Uenglish-listU ##47V7ND7S7a7S7a#and#7a7:S7PV7a7ND7S5#and#7:S5#7G7W7G7W43 1(ormat#nil#Uenglish-listU#C133########==/#44 1(ormat#nil#Uenglish-listU#C1033#######==/#404 1(ormat#nil#Uenglish-listU#C10#!33#####==/#40#and#!4 1(ormat#nil#Uenglish-listU#C10#!#333###==/#405#!5#and#34 1(ormat#nil#Uenglish-listU#C10#!#3#433#==/#405#!5#35#and#44
While th#t control !tring ?erge! on being H6rite-onlyH code, it@! not too h#rd to under!t#nd i' you t#9e it # bit #t # ti*e. &he outer 7V...7T 6ill con!u*e #nd iter#te o?er # li!t. &he 6hole body o' the iter#tion then con!i!t! o' # 7ND...7GG the output gener#ted e#ch ti*e through the iter#tion 6ill thu! depend on the nu*ber o' ite*! le't to be proce!!ed 'ro* the li!t. Splitting #p#rt the 7ND...7G directi?e on the 7S cl#u!e !ep#r#tor!, you c#n !ee th#t it@! *#de up o' 'our cl#u!e!, the l#!t o' 6hich i! # de'#ult cl#u!e bec#u!e it@! preceded by # 7:S r#ther th#n # pl#in 7S. &he 'ir!t cl#u!e, 'or 6hen there #re Aero ele*ent! to be proce!!ed, i! e*pty, 6hich *#9e! !en!e--i' there #re no *ore ele*ent! to be proce!!ed, the iter#tion 6ould@?e !topped #lre#dy. &he !econd cl#u!e h#ndle! the c#!e o' one ele*ent 6ith # !i*ple 7a directi?e. &6o ele*ent! #re h#ndled 6ith 47a#and#7a4. %nd the de'#ult cl#u!e, 6hich h#ndle! three or *ore ele*ent!, con!i!t! o' #nother iter#tion directi?e, thi! ti*e u!ing 7PV to iter#te o?er the re*#ining ele*ent! o' the li!t being proce!!ed by the outer 7V. %nd the body o' th#t iter#tion i! the control !tring th#t c#n h#ndle # li!t o' three or *ore ele*ent! correctly, 6hich i! 'ine in thi! conte.t. 7ec#u!e the 7PV loop con!u*e! #ll the re*#ining li!t ite*!, the outer loop iter#te! only once. I' you 6#nted to print !o*ething !peci#l !uch #! HXe*ptyVH 6hen the li!t 6#! e*pty, you h#?e # couple 6#y! to do it. Perh#p! the e#!ie!t i! to put the te.t you 6#nt into the 'ir!t BAerothC cl#u!e o' the outer 7ND #nd then #dd # colon *odi'ier to the clo!ing 7T o' the outer iter#tion--the colon 'orce! the iter#tion to be run #t le#!t once, e?en i' the li!t i! e*pty, #t 6hich point FORMAT proce!!e! the Aeroth cl#u!e o' the condition#l directi?e.
1de(parameter#Uenglish-listU ##47V7NDOempt?/7S7a7S7a#and#7a7:S7PV7a7ND7S5#and#7:S5#7G7W7G7:W43 1(ormat#nil#Uenglish-listU#C133#==/#4Oempt?/4
%*#Aingly, the 7V directi?e pro?ide! e?en *ore ?#ri#tion! 6ith di''erent co*bin#tion! o' pre'i. p#r#*eter! #nd *odi'ier!. I 6on@t di!cu!! the* other th#n to !#y you c#n u!e #n integer pre'i. p#r#*eter to li*it the *#.i*u* nu*ber o' iter#tion! #nd th#t, 6ith # colon *odi'ier, e#ch ele*ent o' the li!t Beither #n #ctu#l li!t or the li!t con!tructed by the 7PV directi?eC *u!t it!el' be # li!t 6ho!e ele*ent! 6ill then be u!ed #! #rgu*ent! to the control !tring in the 7:V...7T directi?e.
5r you could i*ple*ent # directi?e !i*il#r to 7:T 'or #n irregul#r plur#l by co*bing 7:U 6ith 7D.
1(ormat#nil#49#saw#7r#el7:U7Dves7S(7:Sves7G.4# 3#==/#49#saw#*ero#elves.4 1(ormat#nil#49#saw#7r#el7:U7Dves7S(7:Sves7G.4#03#==/#49#saw#one#el(.4 1(ormat#nil#49#saw#7r#el7:U7Dves7S(7:Sves7G.4#!3#==/#49#saw#two#elves.4
In thi! control !tring, the 7. print! the 'or*#t #rgu*ent #! # c#rdin#l nu*ber. &hen the 7:U directi?e b#c9! up !o the nu*ber i! #l!o u!ed #! the #rgu*ent to the 7D directi?e, !electing bet6een the cl#u!e! 'or 6hen the nu*ber i! Aero, one, or #nything el!e.2 Within #n 7V directi?e, 7U !9ip! or b#c9! up o?er the ite*! in the li!t. /or in!t#nce, you could print
&he 7U directi?e c#n #l!o be gi?en # pre'i. p#r#*eter. With no *odi'ier! or 6ith the colon *odi'ier, thi! p#r#*eter !peci'ie! the nu*ber o' #rgu*ent! to *o?e 'or6#rd or b#c96#rd #nd de'#ult! to one. With #n #t-!ign *odi'ier, the pre'i. p#r#*eter !peci'ie! #n #b!olute, Aero-b#!ed inde. o' the #rgu*ent to <u*p to, de'#ulting to Aero. &he #t-!ign ?#ri#nt o' 7U c#n be u!e'ul i' you 6#nt to u!e di''erent control !tring! to gener#te di''erent *e!!#ge! 'or the !#*e #rgu*ent! #nd i' di''erent *e!!#ge! need to u!e the #rgu*ent! in di''erent order!.,
And +ore . . .
%nd there@! *ore--I h#?en@t *entioned the 7? directi?e, 6hich c#n t#9e !nippet! o' control !tring! 'ro* the 'or*#t #rgu*ent! or the 7/ directi?e, 6hich #llo6! you to c#ll #n #rbitr#ry 'unction to h#ndle the ne.t 'or*#t #rgu*ent. %nd then there #re #ll the directi?e! 'or gener#ting t#bul#r #nd pretty-printed output. 7ut the directi?e! di!cu!!ed in thi! ch#pter !hould be plenty 'or the ti*e being. In the ne.t ch#pter, you@ll *o?e onto Co**on i!p@! condition !y!te*, the Co**on i!p #n#log to other l#ngu#ge!@ e.ception #nd error h#ndling !y!te*!.
15'
cour!e, *o!t 'ol9! re#liAe it@! not 6orth getting th#t 6or9ed up o?er an0thing in # progr#**ing l#ngu#ge #nd u!e it or not 6ithout # lot o' #ng!t. 5n the other h#nd, it@! intere!ting th#t the!e t6o 'e#ture! #re the t6o 'e#ture! in Co**on i!p th#t i*ple*ent 6h#t #re e!!enti#lly do*#in-!peci'ic l#ngu#ge! u!ing # !ynt#. not b#!ed on !-e.pre!!ion!. &he !ynt#. o' FORMAT@! control !tring! i! ch#r#cter b#!ed, 6hile the e.tended LOOP *#cro c#n be under!tood only in ter*! o' the gr#**#r o' the LOOP 9ey6ord!. &h#t one o' the co**on 9noc9! on both FORMAT #nd LOOP i! th#t they H#ren@t i!py enoughH i! e?idence th#t i!per! re#lly do li9e the !-e.pre!!ion !ynt#..
2$e#der!
intere!ted in the pretty printer *#y 6#nt to re#d the p#per HNP: % Co**on i!p Pretty Printing Sy!te*H by $ich#rd W#ter!. It@! # de!cription o' the pretty printer th#t 6#! e?entu#lly incorpor#ted into Co**on i!p. 4ou c#n do6nlo#d it 'ro* (tp://p'blications.ai.mit.ed'/ai-p'blications/pd(/I9%-00 !a.pd(.
3&o
!lightly con'u!e *#tter!, *o!t other I;5 'unction! #l!o #ccept T #nd NIL #! stream designators but 6ith # di''erent *e#ning: #! # !tre#* de!ign#tor, T de!ign#te! the bidirection#l !tre#* *TERMINALIO*, 6hile NIL de!ign#te! *STANDARD-OUTPUT* #! #n output !tre#* #nd *STANDARD-INPUT* #! #n input !tre#*.
-&hi!
?#ri#nt on the 7$ directi?e *#9e! *ore !en!e on pl#t'or*! li9e the i!p 3#chine! 6here 9ey pre!! e?ent! 6ere repre!ented by i!p ch#r#cter!.
5&echnic#lly,
i' the #rgu*ent i!n@t # re#l nu*ber, 7E i! !uppo!ed to 'or*#t it #! i' by the 7< directi?e, 6hich in turn beh#?e! li9e the 7I directi?e i' the #rgu*ent i!n@t # nu*ber, but not #ll i*ple*ent#tion! get thi! right.
0Well,
th#t@! 6h#t the l#ngu#ge !t#nd#rd !#y!. /or !o*e re#!on, perh#p! rooted in # co**on #nce!tr#l code b#!e, !e?er#l Co**on i!p i*ple*ent#tion! don@t i*ple*ent thi! #!pect o' the 7E directi?e correctly.
2I'
you 'ind HI !#6 Aero el?e!H to be # bit clun9y, you could u!e # !lightly *ore el#bor#te 'or*#t !tring
&hi! 9ind o' proble* c#n #ri!e 6hen trying to loc#liAe #n #pplic#tion #nd tr#n!l#te hu*#n-re#d#ble *e!!#ge! into di''erent l#ngu#ge!. FORMAT c#n help 6ith !o*e o' the!e proble*! but i! by no *e#n! # 'ull-blo6n loc#liA#tion !y!te*.
&he condition !y!te* i! *ore 'le.ible th#n e.ception !y!te*! bec#u!e in!te#d o' pro?iding # t6o-p#rt di?i!ion bet6een the code th#t !ign#l! #n error1 #nd the code th#t h#ndle! it,2 the condition !y!te* !plit! the re!pon!ibilitie! into three p#rt!--signaling # condition, handling it, #nd restarting. In thi! ch#pter, I@ll de!cribe ho6 you could u!e condition! in p#rt o' # hypothetic#l #pplic#tion 'or #n#lyAing log 'ile!. 4ou@ll !ee ho6 you could u!e the condition !y!te* to #llo6 # lo6-le?el 'unction to detect # proble* 6hile p#r!ing # log 'ile #nd !ign#l #n error, to #llo6 *id-le?el code to pro?ide !e?er#l po!!ible 6#y! o' reco?ering 'ro* !uch #n error, #nd to #llo6 code #t the highe!t le?el o' the #pplic#tion to de'ine # policy 'or choo!ing 6hich reco?ery !tr#tegy to u!e. &o !t#rt, I@ll introduce !o*e ter*inology: errors, #! I@ll u!e the ter*, #re the con!eFuence! o' 3urphy@! l#6. I' !o*ething c#n go 6rong, it 6ill: # 'ile th#t your progr#* need! to re#d 6ill be *i!!ing, # di!9 th#t you need to 6rite to 6ill be 'ull, the !er?er you@re t#l9ing to 6ill cr#!h, or the net6or9 6ill go do6n. I' #ny o' the!e thing! h#ppen, it *#y !top # piece o' code 'ro* doing 6h#t you 6#nt. 7ut there@! no bugG there@! no pl#ce in the code th#t you c#n 'i. to *#9e the none.i!tent 'ile e.i!t or the di!9 not be 'ull. >o6e?er, i' the re!t o' the progr#* i! depending on the #ction! th#t 6ere going to be t#9en, then you@d better de#l 6ith the error !o*eho6 or you will h#?e introduced # bug. So, error! #ren@t c#u!ed by bug!, but neglecting to h#ndle #n error i! #l*o!t cert#inly # bug. So, 6h#t doe! it *e#n to h#ndle #n error" In # 6ell-6ritten progr#*, e#ch 'unction i! # bl#c9 bo. hiding it! inner 6or9ing!. Progr#*! #re then built out o' l#yer! o' 'unction!: high-le?el 'unction! #re built on top o' the lo6er-le?el 'unction!, #nd !o on. &hi! hier#rchy o' 'unction#lity *#ni'e!t! it!el' #t runti*e in the 'or* o' the c#ll !t#c9: i' high c#ll! medi'm, 6hich c#ll! low, 6hen the 'lo6 o' control i! in low, it@! #l!o !till in medi'm #nd high, th#t i!, they@re !till on the c#ll !t#c9. 7ec#u!e e#ch 'unction i! # bl#c9 bo., 'unction bound#rie! #re #n e.cellent pl#ce to de#l 6ith error!. (#ch 'unction--low, 'or e.#*ple--h#! # <ob to do. It! direct c#ller--medi'm in thi! c#!e--i! counting on it to do it! <ob. >o6e?er, #n error th#t pre?ent! it 'ro* doing it! <ob put! #ll it! c#ller! #t ri!9: medi'm c#lled low bec#u!e it need! the 6or9 done th#t low doe!G i' th#t 6or9 doe!n@t get done, medi'm i! in trouble. 7ut thi! *e#n! th#t medi'm@! c#ller, high, i! #l!o in trouble--#nd !o on up the c#ll !t#c9 to the ?ery top o' the progr#*. 5n the other h#nd, bec#u!e e#ch 'unction i! # bl#c9 bo., i' #ny o' the 'unction! in the c#ll !t#c9 c#n !o*eho6 do their <ob de!pite underlying error!, then none o' the 'unction! #bo?e it need! to 9no6 there 6#! # proble*--#ll tho!e 'unction! c#re #bout i! th#t the 'unction they c#lled !o*eho6 did the 6or9 e.pected o' it. In *o!t l#ngu#ge!, error! #re h#ndled by returning 'ro* # '#iling 'unction #nd gi?ing the c#ller the choice o' either reco?ering or '#iling it!el'. So*e l#ngu#ge! u!e the nor*#l 'unction return *ech#ni!*, 6hile l#ngu#ge! 6ith e.ception! return control by throwing or raising #n e.ception. (.ception! #re # ?#!t i*pro?e*ent o?er u!ing nor*#l 'unction return!, but both !che*e! !u''er 'ro* # co**on 'l#6: 6hile !e#rching 'or # 'unction th#t c#n reco?er, the !t#c9 un6ind!, 6hich *e#n! code th#t *ight reco?er h#! to do !o 6ithout the conte.t o' 6h#t the lo6er-le?el code 6#! trying to do 6hen the error #ctu#lly occurred. Con!ider the hypothetic#l c#ll ch#in o' high, medi'm, low. I' low '#il! #nd medi'm c#n@t reco?er, the b#ll i! in high@! court. /or high to h#ndle the error, it *u!t either do it! <ob 6ithout #ny help 'ro* medi'm or !o*eho6 ch#nge thing! !o c#lling medi'm 6ill 6or9 #nd c#ll it #g#in. &he 'ir!t option i! theoretic#lly cle#n but i*plie! # lot o' e.tr# code--# 6hole e.tr# i*ple*ent#tion o' 6h#te?er it 6#! medi'm 6#! !uppo!ed to do. %nd the 'urther the !t#c9 un6ind!, the *ore 6or9 th#t need! to be redone. &he !econd option--p#tching thing! up #nd retrying--i! tric9yG 'or high to be #ble to ch#nge the !t#te o' the 6orld !o # !econd c#ll into medi'm 6on@t end up c#u!ing #n error in low, it@d need #n un!ee*ly 9no6ledge o' the inner 6or9ing! o' both medi'm #nd low, contr#ry to the notion th#t e#ch 'unction i! # bl#c9 bo..
#onditions
% condition i! #n ob<ect 6ho!e cl#!! indic#te! the gener#l n#ture o' the condition #nd 6ho!e in!t#nce d#t# c#rrie! in'or*#tion #bout the det#il! o' the p#rticul#r circu*!t#nce! th#t le#d to the condition being !ign#led.3 In thi! hypothetic#l log #n#ly!i! progr#*, you *ight de'ine # condition cl#!!, mal(ormed-log-entr?-error, th#t parse-log-entr? 6ill !ign#l i' it@! gi?en d#t# it c#n@t p#r!e. Condition cl#!!e! #re de'ined 6ith the DEFINE-CONDITION *#cro, 6hich 6or9! e!!enti#lly the !#*e #! DEFCLASS e.cept th#t the de'#ult !upercl#!! o' cl#!!e! de'ined 6ith DEFINE-CONDITION i! CONDITION r#ther th#n STANDARD-OB4ECT. Slot! #re !peci'ied in the !#*e 6#y, #nd condition cl#!!e! c#n !ingly #nd *ultiply inherit 'ro* other cl#!!e! th#t de!cend 'ro* CONDITION. 7ut 'or hi!toric#l re#!on!, condition cl#!!e! #ren@t reFuired to be in!t#nce! o' STANDARD-OB4ECT, !o !o*e o' the 'unction! you u!e 6ith DEFCLASSed cl#!!e! #ren@t reFuired to 6or9 6ith condition!. In p#rticul#r, # condition@! !lot! c#n@t be #cce!!ed u!ing SLOT-VALUEG you *u!t !peci'y either # :reader option or #n :accessor option 'or #ny !lot 6ho!e ?#lue you intend to u!e. i9e6i!e, ne6 condition ob<ect! #re cre#ted 6ith MA+E-CONDITION r#ther th#n MA+E-INSTANCE. MA+ECONDITION initi#liAe! the !lot! o' the ne6 condition b#!ed on the :initarg! it@! p#!!ed, but there@! no 6#y to 'urther cu!to*iAe # condition@! initi#liA#tion, eFui?#lent to INITIALI3E-INSTANCE.When u!ing the condition !y!te* 'or error h#ndling, you !hould de'ine your condition! #! !ubcl#!!e! o' ERROR, # !ubcl#!! o' CONDITION. &hu!, you *ight de'ine mal(ormed-log-entr?-error, 6ith # !lot to hold the #rgu*ent th#t 6#! p#!!ed to parse-log-entr?, li9e thi!:
1de(ine-condition#mal(ormed-log-entr?-error#1error3 ##11te)t#:initarg#:te)t#:reader#te)t333
#ondition .and%ers
In parse-log-entr? you@ll !ign#l # mal(ormed-log-entr?-error i' you c#n@t p#r!e the log entry. 4ou !ign#l error! 6ith the 'unction ERROR, 6hich c#ll! the lo6er-le?el 'unction SIGNAL #nd
drop! into the debugger i' the condition i!n@t h#ndled. 4ou c#n c#ll ERROR t6o 6#y!: you c#n p#!! it #n #lre#dy in!t#nti#ted condition ob<ect, or you c#n p#!! it the n#*e o' the condition cl#!! #nd #ny init#rg! needed to con!truct # ne6 condition, #nd it 6ill in!t#nti#te the condition 'or you. &he 'or*er i! occ#!ion#lly u!e'ul 'or re!ign#ling #n e.i!ting condition ob<ect, but the l#tter i! *ore conci!e. &hu!, you could 6rite parse-log-entr? li9e thi!, eliding the det#il! o' #ctu#lly p#r!ing # log entry:
1de('n#parse-log-entr?#1te)t3 ##1i(#1well-(ormed-log-entr?-p#te)t3 ####1ma&e-instance#Clog-entr?#...3 ####1error#Cmal(ormed-log-entr?-error#:te)t#te)t333
Wh#t h#ppen! 6hen the error i! !ign#led depend! on the code #bo?e parse-log-entr? on the c#ll !t#c9. &o #?oid l#nding in the debugger, you *u!t e!t#bli!h # condition handler in one o' the 'unction! le#ding to the c#ll to parse-log-entr?. When # condition i! !ign#led, the !ign#ling *#chinery loo9! through # li!t o' #cti?e condition h#ndler!, loo9ing 'or # h#ndler th#t c#n h#ndle the condition being !ign#led b#!ed on the condition@! cl#!!. (#ch condition h#ndler con!i!t! o' # type !peci'ier indic#ting 6h#t type! o' condition! it c#n h#ndle #nd # 'unction th#t t#9e! # !ingle #rgu*ent, the condition. %t #ny gi?en *o*ent there c#n be *#ny #cti?e condition h#ndler! e!t#bli!hed #t ?#riou! le?el! o' the c#ll !t#c9. When # condition i! !ign#led, the !ign#ling *#chinery 'ind! the *o!t recently e!t#bli!hed h#ndler 6ho!e type !peci'ier i! co*p#tible 6ith the condition being !ign#led #nd c#ll! it! 'unction, p#!!ing it the condition ob<ect. &he h#ndler 'unction c#n then choo!e 6hether to h#ndle the condition. &he 'unction c#n decline to h#ndle the condition by !i*ply returning nor*#lly, in 6hich c#!e control return! to the SIGNAL 'unction, 6hich 6ill !e#rch 'or the ne.t *o!t recently e!t#bli!hed h#ndler 6ith # co*p#tible type !peci'ier. &o h#ndle the condition, the 'unction *u!t tr#n!'er control out o' SIGNAL ?i# # nonlocal e3it. In the ne.t !ection, you@ll !ee ho6 # h#ndler c#n choo!e 6here to tr#n!'er control. >o6e?er, *#ny condition h#ndler! !i*ply 6#nt to un6ind the !t#c9 to the pl#ce 6here they 6ere e!t#bli!hed #nd then run !o*e code. &he *#cro HANDLER-CASE e!t#bli!he! thi! 9ind o' condition h#ndler. &he b#!ic 'or* o' # HANDLER-CASE i! #! 'ollo6!:
1handler-case#expression ##error-clauseU3
I' the e3pression return! nor*#lly, then it! ?#lue i! returned by the HANDLER-CASE. &he body o' # HANDLER-CASE *u!t be # !ingle e.pre!!ionG you c#n u!e PROGN to co*bine !e?er#l e.pre!!ion! into # !ingle 'or*. I', ho6e?er, the e.pre!!ion !ign#l! # condition th#t@! #n in!t#nce o' #ny o' the condition) t0pe! !peci'ied in #ny error)clause, then the code in the #ppropri#te error cl#u!e i! e.ecuted #nd it! ?#lue returned by the HANDLER-CASE. &he var, i' included, i! the n#*e o' the ?#ri#ble th#t 6ill hold the condition ob<ect 6hen the h#ndler code i! e.ecuted. I' the code doe!n@t need to #cce!! the condition ob<ect, you c#n o*it the ?#ri#ble n#*e. /or in!t#nce, one 6#y to h#ndle the mal(ormed-log-entr?-error !ign#led by parse-logentr? in it! c#ller, parse-log-(ile, 6ould be to !9ip the *#l'or*ed entry. In the 'ollo6ing 'unction, the HANDLER-CASE e.pre!!ion 6ill either return the ?#lue returned by parse-logentr? or return NIL i' # mal(ormed-log-entr?-error i! !ign#led. B&he it in the LOOP cl#u!e collect#it i! #nother LOOP 9ey6ord, 6hich re'er! to the ?#lue o' the *o!t recently e?#lu#ted condition#l te!t, in thi! c#!e the ?#lue o' entr?.C
When parse-log-entr? return! nor*#lly, it! ?#lue 6ill be #!!igned to entr? #nd collected by the LOOP. 7ut i' parse-log-entr? !ign#l! # mal(ormed-log-entr?-error, then the error cl#u!e 6ill return NIL, 6hich 6on@t be collected. D%1%-S&4 ( (NC(P&5: >%:+ I:= HANDLER-CASE i! the ne#re!t #n#log in Co**on i!p to D#?#- or Python-!tyle e.ception h#ndling. Where you *ight 6rite thi! in D#?#:
tr?#V ##do,t'((13S ##do%ore,t'((13S W#catch#1,ome-)ception#se3#V ##recover1se3S W
or thi! in Python:
tr?: ##do,t'((13 ##do%ore,t'((13 e)cept#,ome-)ception5#se: ##recover1se3
&hi! ?er!ion o' parse-log-(ile h#! one !eriou! de'iciency: it@! doing too *uch. %! it! n#*e !ugge!t!, the <ob o' parse-log-(ile i! to p#r!e the 'ile #nd produce # li!t o' log-entr? ob<ect!G i' it c#n@t, it@! not it! pl#ce to decide 6h#t to do in!te#d. Wh#t i' you 6#nt to u!e parse-log-(ile in #n #pplic#tion th#t 6#nt! to tell the u!er th#t the log 'ile i! corrupted or one th#t 6#nt! to reco?er 'ro* *#l'or*ed entrie! by 'i.ing the* up #nd re-p#r!ing the*" 5r *#ybe #n #pplic#tion i! 'ine 6ith !9ipping the* but only until # cert#in nu*ber o' corrupted entrie! h#?e been !een. 4ou could try to 'i. thi! proble* by *o?ing the HANDLER-CASE to # higher-le?el 'unction. >o6e?er, then you@d h#?e no 6#y to i*ple*ent the current policy o' !9ipping indi?idu#l entrie!--6hen the error 6#! !ign#led, the !t#c9 6ould be un6ound #ll the 6#y to the higher-le?el 'unction, #b#ndoning the p#r!ing o' the log 'ile #ltogether. Wh#t you 6#nt i! # 6#y to pro?ide the current reco?ery !tr#tegy 6ithout reFuiring th#t it #l6#y! be u!ed.
Restarts
&he condition !y!te* let! you do thi! by !plitting the error h#ndling code into t6o p#rt!. 4ou pl#ce
code th#t #ctu#lly reco?er! 'ro* error! into restarts, #nd condition h#ndler! c#n then h#ndle # condition by in?o9ing #n #ppropri#te re!t#rt. 4ou c#n pl#ce re!t#rt code in *id- or lo6-le?el 'unction!, !uch #! parse-log-(ile or parse-log-entr?, 6hile *o?ing the condition h#ndler! into the upper le?el! o' the #pplic#tion. &o ch#nge parse-log-(ile !o it e!t#bli!he! # re!t#rt in!te#d o' # condition h#ndler, you c#n ch#nge the HANDLER-CASE to # RESTART-CASE. &he 'or* o' RESTART-CASE i! Fuite !i*il#r to # HANDLER-CASE e.cept the n#*e! o' re!t#rt! #re <u!t n#*e!, not nece!!#rily the n#*e! o' condition type!. In gener#l, # re!t#rt n#*e !hould de!cribe the #ction the re!t#rt t#9e!. In parse-log-(ile, you c#n c#ll the re!t#rt s&ip-log-entr? !ince th#t@! 6h#t it doe!. &he ne6 ?er!ion 6ill loo9 li9e thi!:
1de('n#parse-log-(ile#1(ile3 ##1with-open-(ile#1in#(ile#:direction#:inp't3 ####1loop#(or#te)t#=#1read-line#in#nil#nil3#while#te)t #######(or#entr?#=#1restart-case#1parse-log-entr?#te)t3 #####################1s&ip-log-entr?#13#nil33 #######when#entr?#collect#it333
I' you in?o9e thi! ?er!ion o' parse-log-(ile on # log 'ile cont#ining corrupted entrie!, it 6on@t h#ndle the error directlyG you@ll end up in the debugger. >o6e?er, there #*ong the ?#riou! re!t#rt! pre!ented by the debugger 6ill be one c#lled s&ip-log-entr?, 6hich, i' you choo!e it, 6ill c#u!e parse-log-(ile to continue on it! 6#y #! be'ore. &o #?oid ending up in the debugger, you c#n e!t#bli!h # condition h#ndler th#t in?o9e! the s&ip-log-entr? re!t#rt #uto*#tic#lly. &he #d?#nt#ge o' e!t#bli!hing # re!t#rt r#ther th#n h#?ing parse-log-(ile h#ndle the error directly i! it *#9e! parse-log-(ile u!#ble in *ore !itu#tion!. &he higher-le?el code th#t in?o9e! parselog-(ile doe!n@t h#?e to in?o9e the s&ip-log-entr? re!t#rt. It c#n choo!e to h#ndle the error #t # higher le?el. 5r, #! I@ll !ho6 in the ne.t !ection, you c#n #dd re!t#rt! to parse-log-entr? to pro?ide other reco?ery !tr#tegie!, #nd then condition h#ndler! c#n choo!e 6hich !tr#tegy they 6#nt to u!e. 7ut be'ore I c#n t#l9 #bout th#t, you need to !ee ho6 to !et up # condition h#ndler th#t 6ill in?o9e the s&ip-log-entr? re!t#rt. 4ou c#n !et up the h#ndler #ny6here in the ch#in o' c#ll! le#ding to parse-log-(ile. &hi! *#y be Fuite high up in your #pplic#tion, not nece!!#rily in parse-log(ile@! direct c#ller. /or in!t#nce, !uppo!e the *#in entry point to your #pplic#tion i! # 'unction, loganal?*er, th#t 'ind! # bunch o' log! #nd #n#lyAe! the* 6ith the 'unction anal?*e-log, 6hich e?entu#lly le#d! to # c#ll to parse-log-(ile. Without #ny error h#ndling, it *ight loo9 li9e thi!:
1de('n#log-anal?*er#13 ##1dolist#1log#1(ind-all-logs33 ####1anal?*e-log#log333
&he <ob o' anal?*e-log i! to c#ll, directly or indirectly, parse-log-(ile #nd then do !o*ething 6ith the li!t o' log entrie! returned. %n e.tre*ely !i*ple ?er!ion *ight loo9 li9e thi!:
1de('n#anal?*e-log#1log3 ##1dolist#1entr?#1parse-log-(ile#log33 ####1anal?*e-entr?#entr?333
6here the 'unction anal?*e-entr? i! pre!u*#bly re!pon!ible 'or e.tr#cting 6h#te?er in'or*#tion you c#re #bout 'ro* e#ch log entry #nd !t#!hing it #6#y !o*e6here. &hu!, the p#th 'ro* the top-le?el 'unction, log-anal?*er, to parse-log-entr?, 6hich #ctu#lly
%!!u*ing you #l6#y! 6#nt to !9ip *#l'or*ed log entrie!, you could ch#nge thi! 'unction to e!t#bli!h # condition h#ndler th#t in?o9e! the s&ip-log-entr? re!t#rt 'or you. >o6e?er, you c#n@t u!e HANDLER-CASE to e!t#bli!h the condition h#ndler bec#u!e then the !t#c9 6ould be un6ound to the 'unction 6here the HANDLER-CASE #ppe#r!. In!te#d, you need to u!e the lo6er-le?el *#cro HANDLER-BIND. &he b#!ic 'or* o' HANDLER-BIND i! #! 'ollo6!:
1handler-bind#1bindingU3#formU3
6here e#ch binding i! # li!t o' # condition type #nd # h#ndler 'unction o' one #rgu*ent. %'ter the h#ndler binding!, the body o' the HANDLER-BIND c#n cont#in #ny nu*ber o' 'or*!. 8nli9e the h#ndler code in HANDLER-CASE, the h#ndler code *u!t be # 'unction ob<ect, #nd it *u!t #ccept # !ingle #rgu*ent. % *ore i*port#nt di''erence bet6een HANDLER-BIND #nd HANDLER-CASE i! th#t the h#ndler 'unction bound by HANDLER-BIND 6ill be run 6ithout un6inding the !t#c9--the 'lo6 o' control 6ill !till be in the c#ll to parse-log-entr? 6hen thi! 'unction i! c#lled. &he c#ll to INVO+E-RESTART 6ill 'ind #nd in?o9e the *o!t recently bound re!t#rt 6ith the gi?en n#*e. So you c#n #dd # h#ndler to log-anal?*er th#t 6ill in?o9e the s&ip-log-entr? re!t#rt e!t#bli!hed in parse-log-(ile li9e thi!:5
1de('n#log-anal?*er#13 ##1handler-bind#11mal(ormed-log-entr?-error ##################NC1lambda#1c3 ######################1invo&e-restart#Cs&ip-log-entr?3333 ####1dolist#1log#1(ind-all-logs33 ######1anal?*e-log#log3333
In thi! HANDLER-BIND, the h#ndler 'unction i! #n #nony*ou! 'unction th#t in?o9e! the re!t#rt s&ip-log-entr?. 4ou could #l!o de'ine # n#*ed 'unction th#t doe! the !#*e thing #nd bind it in!te#d. In '#ct, # co**on pr#ctice 6hen de'ining # re!t#rt i! to de'ine # 'unction, 6ith the !#*e n#*e #nd t#9ing # !ingle #rgu*ent, the condition, th#t in?o9e! the epony*ou! re!t#rt. Such 'unction! #re c#lled restart functions. 4ou could de'ine # re!t#rt 'unction 'or s&ip-log-entr? li9e thi!:
1de('n#s&ip-log-entr?#1c3 ##1invo&e-restart#Cs&ip-log-entr?33
%! 6ritten, the s&ip-log-entr? re!t#rt 'unction #!!u*e! th#t # s&ip-log-entr? re!t#rt h#!
been e!t#bli!hed. I' # mal(ormed-log-entr?-error i! e?er !ign#led by code c#lled 'ro* loganal?*er 6ithout # s&ip-log-entr? h#?ing been e!t#bli!hed, the c#ll to INVO+E-RESTART 6ill !ign#l # CONTROL-ERROR 6hen it '#il! to 'ind the s&ip-log-entr? re!t#rt. I' you 6#nt to #llo6 'or the po!!ibility th#t # mal(ormed-log-entr?-error *ight be !ign#led 'ro* code th#t doe!n@t h#?e # s&ip-log-entr? re!t#rt e!t#bli!hed, you could ch#nge the s&ip-log-entr? 'unction to thi!:
1de('n#s&ip-log-entr?#1c3 ##1let#11restart#1(ind-restart#Cs&ip-log-entr?333 ####1when#restart#1invo&e-restart#restart3333
FIND-RESTART loo9! 'or # re!t#rt 6ith # gi?en n#*e #nd return! #n ob<ect repre!enting the re!t#rt i' the re!t#rt i! 'ound #nd NIL i' not. 4ou c#n in?o9e the re!t#rt by p#!!ing the re!t#rt ob<ect to INVO+ERESTART. &hu!, 6hen s&ip-log-entr? i! bound 6ith HANDLER-BIND, it 6ill h#ndle the condition by in?o9ing the s&ip-log-entr? re!t#rt i' one i! #?#il#ble #nd other6i!e 6ill return nor*#lly, gi?ing other condition h#ndler!, bound higher on the !t#c9, # ch#nce to h#ndle the condition.
&he n#*e USE-VALUE i! # !t#nd#rd n#*e 'or thi! 9ind o' re!t#rt. Co**on i!p de'ine! # re!t#rt 'unction 'or USE-VALUE !i*il#r to the s&ip-log-entr? 'unction you <u!t de'ined. So, i' you 6#nted to ch#nge the policy on *#l'or*ed entrie! to one th#t cre#ted #n in!t#nce o' mal(ormedlog-entr?, you could ch#nge log-anal?*er to thi! B#!!u*ing the e.i!tence o' # mal(ormedlog-entr? cl#!! 6ith # :te)t init#rgC:
1de('n#log-anal?*er#13 ##1handler-bind#11mal(ormed-log-entr?-error ##################NC1lambda#1c3 ######################1'se-val'e #######################1ma&e-instance#Cmal(ormed-log-entr?#:te)t#1te)t#c333333 ####1dolist#1log#1(ind-all-logs33 ######1anal?*e-log#log3333
4ou could #l!o h#?e put the!e ne6 re!t#rt! into parse-log-(ile in!te#d o' parse-log-entr?. >o6e?er, you gener#lly 6#nt to put re!t#rt! in the lo6e!t-le?el code po!!ible. It 6ouldn@t, though, be #ppropri#te to *o?e the s&ip-log-entr? re!t#rt into parse-log-entr? !ince th#t 6ould c#u!e parse-log-entr? to !o*eti*e! return nor*#lly 6ith NIL, the ?ery thing you !t#rted out trying to #?oid. %nd it@d be #n eFu#lly b#d ide# to re*o?e the s&ip-log-entr? re!t#rt on the theory th#t the condition h#ndler could get the !#*e e''ect by in?o9ing the 'se-val'e re!t#rt 6ith NIL #! the #rgu*entG th#t 6ould reFuire the condition h#ndler to h#?e inti*#te 9no6ledge o' ho6 the parselog-(ile 6or9!. %! it !t#nd!, the s&ip-log-entr? i! # properly #b!tr#cted p#rt o' the logp#r!ing %PI.
c#ll to CERROR. &he 'unction CONTINUE 'ind! #nd in?o9e! the CONTINUE re!t#rt i' it@! #?#il#ble #nd return! NIL other6i!e. 4ou c#n #l!o build your o6n protocol! on SIGNAL--6hene?er lo6-le?el code need! to co**unic#te in'or*#tion b#c9 up the c#ll !t#c9 to higher-le?el code, the condition *ech#ni!* i! # re#!on#ble *ech#ni!* to u!e. 7ut 'or *o!t purpo!e!, one o' the !t#nd#rd error or 6#rning protocol! !hould !u''ice. 4ou@ll u!e the condition !y!te* in 'uture pr#ctic#l ch#pter!, both 'or regul#r error h#ndling #nd, in Ch#pter 25, to help in h#ndling # tric9y corner c#!e o' p#r!ing I+3 'ile!. 8n'ortun#tely, it@! the '#te o' error h#ndling to #l6#y! get !hort !hri't in progr#**ing te.t!--proper error h#ndling, or l#c9 thereo', i! o'ten the bigge!t di''erence bet6een illu!tr#ti?e code #nd h#rdened, production-Fu#lity code. &he tric9 to 6riting the l#tter h#! *ore to do 6ith #dopting # p#rticul#rly rigorou! 6#y o' thin9ing #bout !o't6#re th#n 6ith the det#il! o' #ny p#rticul#r progr#**ing l#ngu#ge con!truct!. &h#t !#id, i' your go#l i! to 6rite th#t 9ind o' !o't6#re, you@ll 'ind the Co**on i!p condition !y!te* i! #n e.cellent tool 'or 6riting robu!t code #nd one th#t 'it! Fuite nicely into Co**on i!p@! incre*ent#l de?elop*ent !tyle. Writing $obu!t So't6#re /or in'or*#tion on 6riting robu!t !o't6#re, you could do 6or!e th#n to !t#rt by 'inding # copy o' -oftware *eliabilit0 BDohn Wiley ] Son!, 1)20C by =len'ord D. 3eyer!. 7ertr#nd 3eyer@! 6riting! on +e!ign 7y Contr#ct #l!o pro?ide # u!e'ul 6#y o' thin9ing #bout !o't6#re correctne!!. /or in!t#nce, !ee Ch#pter! 11 #nd 12 o' hi! Object)Oriented -oftware Construction BPrentice >#ll, 1))2C. Leep in *ind, ho6e?er, th#t 7ertr#nd 3eyer i! the in?entor o' (i''el, # !t#tic#lly typed bond#ge #nd di!cipline l#ngu#ge in the %lgol;%d# !chool. While he h#! # lot o' !*#rt thing! to !#y #bout ob<ect orient#tion #nd !o't6#re reli#bility, there@! # '#irly 6ide g#p bet6een hi! ?ie6 o' progr#**ing #nd &he i!p W#y. /in#lly, 'or #n e.cellent o?er?ie6 o' the l#rger i!!ue! !urrounding building '#ult-toler#nt !y!te*!, !ee Ch#pter 3 o' the cl#!!ic Transaction Processing: Concepts and Techni4ues B3org#n L#u'*#nn, 1))3C by Di* =r#y #nd %ndre#! $euter. In the ne.t ch#pter I@ll gi?e # Fuic9 o?er?ie6 o' !o*e o' the 25 !peci#l oper#tor! you h#?en@t h#d # ch#nce to u!e yet, #t le#!t not directly.
1Throws
thi! re!pect, # condition i! # lot li9e #n e.ception in D#?# or Python e.cept not #ll condition! repre!ent #n error or e3ceptional !itu#tion. !o*e Co**on i!p i*ple*ent#tion!, condition! #re de'ined #! !ubcl#!!e! o' STANDARDOB4ECT, in 6hich c#!e SLOT-VALUE, MA+E-INSTANCE, #nd INITIALI3E-INSTANCE 6ill 6or9, but it@! not port#ble to rely on it.
5&he
co*piler *#y co*pl#in i' the p#r#*eter i! ne?er u!ed. 4ou c#n !ilence th#t 6#rning by #dding # decl#r#tion 1declare#1ignore#c33 #! the 'ir!t e.pre!!ion in the LAMBDA body.
in'reFuently !i*ply bec#u!e 6h#te?er need they #ddre!! doe!n@t #ri!e th#t o'ten. It@! good to be '#*ili#r 6ith the!e !peci#l oper#tor! !o 6hen one o' the* i! c#lled 'or, you@ll #t le#!t 9no6 it e.i!t!. Second, bec#u!e the 25 !peci#l oper#tor!--#long 6ith the b#!ic rule 'or e?#lu#ting 'unction c#ll! #nd the built-in d#t# type!--pro?ide the 'ound#tion 'or the re!t o' the l#ngu#ge, # p#!!ing '#*ili#rity 6ith the* 6ill help you under!t#nd ho6 the l#ngu#ge 6or9!. In thi! ch#pter, I@ll di!cu!! #ll the !peci#l oper#tor!, !o*e brie'ly #nd !o*e #t length, !o you c#n !ee ho6 they 'it together. I@ll point out 6hich one! you c#n e.pect to u!e directly in your o6n code, 6hich one! !er?e #! the b#!i! 'or other con!truct! th#t you u!e #ll the ti*e, #nd 6hich one! you@ll r#rely u!e directly but 6hich c#n be h#ndy in *#cro-gener#ted code.
#ontro%%ing !,a%uation
&he 'ir!t c#tegory o' !peci#l oper#tor! cont#in! the three oper#tor! th#t pro?ide b#!ic control o?er the e?#lu#tion o' 'or*!. &hey@re QUOTE, IF, #nd PROGN, #nd I@?e di!cu!!ed the* #ll #lre#dy. >o6e?er, it@! 6orth noting ho6 e#ch o' the!e !peci#l oper#tor! pro?ide! one 'und#*ent#l 9ind o' control o?er the e?#lu#tion o' one or *ore 'or*!. QUOTE pre?ent! e?#lu#tion #ltogether #nd #llo6! you to get #t !e.pre!!ion! #! d#t#. IF pro?ide! the 'und#*ent#l boole#n choice oper#tion 'ro* 6hich #ll other condition#l e.ecution con!truct! c#n be built.1 %nd PROGN pro?ide! the #bility to !eFuence # nu*ber o' 'or*!.
&he di''erence bet6een FLET #nd LABELS i! th#t the n#*e! o' the 'unction! de'ined 6ith FLET c#n be u!ed only in the body o' the FLET, 6hile the n#*e! introduced by LABELS c#n be u!ed i**edi#tely, including in the bodie! o' the 'unction! de'ined by the LABELS. &hu!, LABELS c#n de'ine recur!i?e 'unction!, 6hile FLET c#n@t. It *ight !ee* li*iting th#t FLET c#n@t be u!ed to de'ine recur!i?e 'unction!, but Co**on i!p pro?ide! both FLET #nd LABELS bec#u!e !o*eti*e! it@! u!e'ul to be #ble to 6rite loc#l 'unction! th#t c#n c#ll #nother 'unction o' the !#*e n#*e, either # glob#lly de'ined 'unction or # loc#l 'unction 'ro* #n enclo!ing !cope. Within the body o' # FLET or LABELS, you c#n u!e the n#*e! o' the 'unction! de'ined <u!t li9e #ny other 'unction, including 6ith the FUNCTION !peci#l oper#tor. Since you c#n u!e FUNCTION to get the 'unction ob<ect repre!enting # 'unction de'ined 6ith FLET or LABELS, #nd !ince # FLET or LABELS c#n be in the !cope o' other binding 'or*! !uch #! LET!, the!e 'unction! c#n be clo!ure!. 7ec#u!e the loc#l 'unction! c#n re'er to ?#ri#ble! 'ro* the enclo!ing !cope, they c#n o'ten be 6ritten to t#9e 'e6er p#r#*eter! th#n the eFui?#lent helper 'unction!. &hi! i! p#rticul#rly h#ndy 6hen you need to p#!! # 'unction th#t t#9e! # !ingle #rgu*ent #! # 'unction#l p#r#*eter. /or e.#*ple, in the 'ollo6ing 'unction, 6hich you@ll !ee #g#in in Ch#pter 25, the FLETed 'unction, co'nt-version, t#9e! # !ingle #rgu*ent, #! reFuired by wal&-director?, but c#n #l!o u!e the ?#ri#ble versions, introduced by the enclo!ing LET:
1de('n#co'nt-versions#1dir3 ##1let#11versions#1mapcar#NC1lambda#1)3#1cons#)# 33#C1!#3#43333 ####1(let#11co'nt-version#1(ile3 #############1inc(#1cdr#1assoc#1major-version#1read-id3#(ile33#versions33333 ######1wal&-director?#dir#NCco'nt-version#:test#NCmp3-p33 ####versions33
&hi! 'unction could #l!o be 6ritten u!ing #n #nony*ou! 'unction in the pl#ce o' the FLETed co'ntversion, but gi?ing the 'unction # *e#ning'ul n#*e *#9e! it # bit e#!ier to re#d. %nd 6hen # helper 'unction need! to recur!e, #n #nony*ou! 'unction <u!t 6on@t do.3 When you don@t 6#nt to de'ine # recur!i?e helper 'unction #! # glob#l 'unction, you c#n u!e LABELS. /or e.#*ple, the 'ollo6ing 'unction, collect-leaves, u!e! the recur!i?e helper 'unction wal& to 6#l9 # tree #nd g#ther #ll the #to*! in the tree into # li!t, 6hich collect-leaves then return! B#'ter re?er!ing itC:
1de('n#collect-leaves#1tree3 ##1let#11leaves#1333 ####1labels#11waltree3 ###############1cond #################11n'll#tree33 #################11atom#tree3#1p'sh#tree#leaves33 #################1t#1walcar#tree33 ####################1walcdr#tree333333 ######1wal&#tree33 ####1nreverse#leaves333
:otice #g#in ho6, 6ithin the wal& 'unction, you c#n re'er to the ?#ri#ble, leaves, introduced by the enclo!ing LET. FLET #nd LABELS #re #l!o u!e'ul oper#tion! to u!e in *#cro e.p#n!ion!--# *#cro c#n e.p#nd into code th#t cont#in! # FLET or LABELS to cre#te 'unction! th#t c#n be u!ed 6ithin the body o' the *#cro. &hi! techniFue c#n be u!ed either to introduce 'unction! th#t the u!er o' the *#cro 6ill c#ll or !i*ply #! # 6#y o' org#niAing the code gener#ted by the *#cro. &hi!, 'or in!t#nce, i! ho6 # 'unction !uch #! CALL-NEXT-METHOD, 6hich c#n be u!ed only 6ithin # *ethod de'inition, *ight be de'ined.
% ne#r rel#ti?e to FLET #nd LABELS i! the !peci#l oper#tor MACROLET, 6hich you c#n u!e to de'ine loc#l *#cro!. oc#l *#cro! 6or9 <u!t li9e glob#l *#cro! de'ined 6ith DEFMACRO e.cept 6ithout cluttering the glob#l n#*e!p#ce. When # MACROLET 'or* i! e?#lu#ted, the body 'or*! #re e?#lu#ted 6ith the loc#l *#cro de'inition! in e''ect #nd po!!ibly !h#do6ing glob#l 'unction #nd *#cro de'inition! or loc#l de'inition! 'ro* enclo!ing 'or*!. i9e FLET #nd LABELS, MACROLET c#n be u!ed directly, but it@! #l!o # h#ndy t#rget 'or *#cro-gener#ted code--by 6r#pping !o*e u!er-!upplied code in # MACROLET, # *#cro c#n pro?ide con!truct! th#t c#n be u!ed only 6ithin th#t code or c#n !h#do6 # glob#lly de'ined *#cro. 4ou@ll !ee #n e.#*ple o' thi! l#tter u!e o' MACROLET in Ch#pter 31. /in#lly, one l#!t *#cro-de'ining !peci#l oper#tor i! SYMBOL-MACROLET, 6hich de'ine! # !peci#l 9ind o' *#cro c#lled, #ppropri#tely enough, # s0mbol macro. Sy*bol *#cro! #re li9e regul#r *#cro! e.cept they c#n@t t#9e #rgu*ent! #nd #re re'erred to 6ith # pl#in !y*bol r#ther th#n # li!t 'or*. In other 6ord!, #'ter you@?e de'ined # !y*bol *#cro 6ith # p#rticul#r n#*e, #ny u!e o' th#t !y*bol in # ?#lue po!ition 6ill be e.p#nded #nd the re!ulting 'or* e?#lu#ted in it! pl#ce. &hi! i! ho6 *#cro! !uch #! WITHSLOTS #nd WITH-ACCESSORS #re #ble to de'ine H?#ri#ble!H th#t #cce!! the !t#te o' # p#rticul#r ob<ect under the co?er!. /or in!t#nce, the 'ollo6ing WITH-SLOTS 'or*:
1with-slots#1)#?#*3#(oo#1list#)#?#*333
When the e.pre!!ion 1list#)#?#*3 i! e?#lu#ted, the !y*bol! ), ?, #nd * 6ill be repl#ced 6ith their e.p#n!ion!, !uch #! 1slot-val'e#N:g049#C)3.Sy*bol *#cro! #re *o!t o'ten loc#l, de'ined 6ith SYMBOL-MACROLET, but Co**on i!p #l!o pro?ide! # *#cro DEFINE-SYMBOL-MACRO th#t de'ine! # glob#l !y*bol *#cro. % !y*bol *#cro de'ined 6ith SYMBOL-MACROLET !h#do6! other !y*bol *#cro! o' the !#*e n#*e de'ined 6ith DEFINE-SYMBOL-MACRO or enclo!ing SYMBOL-MACROLET 'or*!.
&he name i! # !y*bol, #nd the forms #re i!p 'or*!. &he 'or*! #re e?#lu#ted in order, #nd the ?#lue o'
the l#!t 'or* i! returned #! the ?#lue o' the BLOC+ unle!! # RETURN-FROM i! u!ed to return 'ro* the bloc9 e#rly. % RETURN-FROM 'or*, #! you !#6 in Ch#pter 5, con!i!t! o' the n#*e o' the bloc9 to return 'ro* #nd, option#lly, # 'or* th#t pro?ide! # ?#lue to return. When # RETURN-FROM i! e?#lu#ted, it c#u!e! the n#*ed BLOC+ to return i**edi#tely. I' RETURN-FROM i! c#lled 6ith # return ?#lue 'or*, the BLOC+ 6ill return the re!ulting ?#lueG other6i!e, the BLOC+ e?#lu#te! to NIL. % BLOC+ n#*e c#n be #ny !y*bol, 6hich include! NIL. 3#ny o' the !t#nd#rd control con!truct *#cro!, !uch #! DO, DOTIMES, #nd DOLIST, gener#te #n e.p#n!ion con!i!ting o' # BLOC+ n#*ed NIL. &hi! #llo6! you to u!e the RETURN *#cro, 6hich i! # bit o' !ynt#ctic !ug#r 'or 1ret'rn-(rom# nil#...3, to bre#9 out o' !uch loop!. &hu!, the 'ollo6ing loop 6ill print #t *o!t ten r#ndo* nu*ber!, !topping #! !oon #! it get! # nu*ber gre#ter th#n 50:
1dotimes#1i#0 3 ##1let#11answer#1random#0 333 ####1print#answer3 ####1i(#1/#answer#" 3#1ret'rn3333
/unction-de'ining *#cro! !uch #! DEFUN, FLET, #nd LABELS, on the other h#nd, 6r#p their bodie! in # BLOC+ 6ith the !#*e n#*e #! the 'unction. &h#t@! 6hy you c#n u!e RETURN-FROM to return 'ro* # 'unction. TAGBODY #nd GO h#?e # !i*il#r rel#tion!hip to e#ch other #! BLOC+ #nd RETURN-FROM: # TAGBODY 'or* de'ine! # conte.t in 6hich n#*e! #re de'ined th#t c#n be u!ed by GO. &he !9eleton o' # TAGBODY i! #! 'ollo6!:
1tagbod? ##tag-or-compound-formU3
6here e#ch tag)or)compound)form i! either # !y*bol, c#lled # tag, or # none*pty li!t 'or*. &he li!t 'or*! #re e?#lu#ted in order #nd the t#g! ignored, e.cept #! I@ll di!cu!! in # *o*ent. %'ter the l#!t 'or* o' the TAGBODY i! e?#lu#ted, the TAGBODY return! NIL. %ny6here 6ithin the le.ic#l !cope o' the TAGBODY you c#n u!e the GO !peci#l oper#tor to <u*p i**edi#tely to #ny o' the t#g!, #nd e?#lu#tion 6ill re!u*e 6ith the 'or* 'ollo6ing the t#g. /or in!t#nce, you c#n 6rite # tri?i#l in'inite loop 6ith TAGBODY #nd GO li9e thi!:
1tagbod? #top ###1print#Chello3 ###1go#top33
:ote th#t 6hile the t#g n#*e! *u!t #ppe#r #t the top le?el o' the TAGBODY, not ne!ted 6ithin other 'or*!, the GO !peci#l oper#tor c#n #ppe#r #ny6here 6ithin the !cope o' the TAGBODY. &hi! *e#n! you could 6rite # loop th#t loop! # r#ndo* nu*ber o' ti*e! li9e thi!:
1tagbod? #top ###1print#Chello3 ###1when#1pl'sp#1random#0 33#1go#top333
%n e?en !illier e.#*ple o' TAGBODY, 6hich !ho6! you c#n h#?e *ultiple t#g! in # !ingle TAGBODY, loo9! li9e thi!:
1tagbod? #a#1print#Ca3#1i(#1*erop#1random#!33#1go#c33 #b#1print#Cb3#1i(#1*erop#1random#!33#1go#a33
#c#1print#Cc3#1i(#1*erop#1random#!33#1go#b333
&hi! 'or* 6ill <u*p #round r#ndo*ly printing a!, b!, #nd c! until e?entu#lly the l#!t RANDOM e.pre!!ion return! 1 #nd the control '#ll! o'' the end o' the TAGBODY. TAGBODY i! r#rely u!ed directly !ince it@! #l*o!t #l6#y! e#!ier to 6rite iter#ti?e con!truct! in ter*! o' the e.i!ting looping *#cro!. It@! h#ndy, ho6e?er, 'or tr#n!l#ting #lgorith*! 6ritten in other l#ngu#ge! into Co**on i!p, either #uto*#tic#lly or *#nu#lly. %n e.#*ple o' #n #uto*#tic tr#n!l#tion tool i! the /5$&$%:-to-Co**on i!p tr#n!l#tor, '2cl, th#t tr#n!l#te! /5$&$%: !ource code into Co**on i!p in order to *#9e ?#riou! /5$&$%: libr#rie! #?#il#ble to Co**on i!p progr#**er!. Since *#ny /5$&$%: libr#rie! 6ere 6ritten be'ore the !tructured progr#**ing re?olution, they@re 'ull o' goto!. &he '2cl co*piler c#n !i*ply tr#n!l#te tho!e goto! to GO! 6ithin #ppropri#te TAGBODY!.5 Si*il#rly, TAGBODY #nd GO c#n be h#ndy 6hen tr#n!l#ting #lgorith*! de!cribed in pro!e or by 'lo6ch#rt!--'or in!t#nce, in +on#ld Lnuth@! cl#!!ic !erie! The !rt of Computer Programming, he de!cribe! #lgorith*! u!ing # HrecipeH 'or*#t: !tep 1, do thi!G !tep 2, do th#tG !tep 3, go b#c9 to !tep 2G #nd !o on. /or e.#*ple, on p#ge 1-2 o' The !rt of Computer Programming< ?olume 5: -eminumerical !lgorithms, &hird (dition B%ddi!on-We!ley, 1)),C, he de!cribe! %lgorith* S, 6hich you@ll u!e in Ch#pter 22, in thi! 'or*: %lgorith* S BSelection !#*pling techniFueC. &o !elect n record! #t r#ndo* 'ro* # !et o' :, 6here 0 X n XU :. S1. JIniti#liAe.K Set t X-- 0, * X-- 0. B+uring thi! #lgorith*, * repre!ent! the nu*ber o' record! !elected !o '#r, #nd t i! the tot#l nu*ber o' input record! th#t 6e h#?e de#lt 6ith.C S2. J=ener#te 8.K =ener#te # r#ndo* nu*ber 8, uni'or*ly di!tributed bet6een Aero #nd one. S3. J&e!t.K I' B: - tC8 VU n - *, go to !tep S5. S-. JSelect.K Select the ne.t record 'or the !#*ple, #nd incre#!e * #nd t by 1. I' * X n, go to !tep S2G other6i!e the !#*ple i! co*plete #nd the #lgorith* ter*in#te!. S5. JS9ip.K S9ip the ne.t record Bdo not include it in the !#*pleC, incre#!e t by 1, #nd go b#c9 to !tep S2. &hi! de!cription c#n be e#!ily tr#n!l#ted into # Co**on i!p 'unction, #'ter ren#*ing # 'e6 ?#ri#ble!, #! 'ollo6!:
1de('n#algorithm-s#1n#ma)3#S#ma)#is#8#in#Mn'thCs#algorithm ##1let#1seen###############S#t#in#Mn'thCs#algorithm ########selected###########S#m#in#Mn'thCs#algorithm ########'##################S#+#in#Mn'thCs#algorithm ########1records#1333######S#the#list#where#we#save#the#records#selected ####1tagbod? #####s0 #######1set(#seen# 3 #######1set(#selected# 3 #####s! #######1set(#'#1random#0. 33 #####s3 #######1when#1/=#1U#1-#ma)#seen3#'3#1-#n#selected33#1go#s"33
#####s4 #######1p'sh#seen#records3 #######1inc(#selected3 #######1inc(#seen3 #######1i(#1O#selected#n3 ###########1go#s!3 ###########1ret'rn-(rom#algorithm-s#1nreverse#records333 #####s" #######1inc(#seen3 #######1go#s!3333
It@! not the prettie!t code, but it@! e#!y to ?eri'y th#t it@! # '#ith'ul tr#n!l#tion o' Lnuth@! #lgorith*. 7ut, thi! code, unli9e Lnuth@! pro!e de!cription, c#n be run #nd te!ted. &hen you c#n !t#rt re'#ctoring, chec9ing #'ter e#ch ch#nge th#t the 'unction !till 6or9!.0 %'ter pu!hing the piece! #round # bit, you *ight end up 6ith !o*ething li9e thi!:
1de('n#algorithm-s#1n#ma)3 ##1loop#(or#seen#(rom# #####when#1O#1U#1-#ma)#seen3#1random#0. 33#n3 #####collect#seen#and#do#1dec(#n3 #####'ntil#1*erop#n333
While it *#y not be i**edi#tely ob?iou! th#t thi! code correctly i*ple*ent! %lgorith* S, i' you got here ?i# # !erie! o' 'unction! th#t #ll beh#?e identic#lly to the origin#l liter#l tr#n!l#tion o' Lnuth@! recipe, you@d h#?e good re#!on to belie?e it@! correct.
&he #nony*ou! 'unction p#!!ed to bar u!e! RETURN-FROM to return 'ro* the BLOC+. 7ut th#t RETURN-FROM doe!n@t get e?#lu#ted until the #nony*ou! 'unction i! in?o9ed 6ith FUNCALL or APPLY. :o6 !uppo!e bar loo9! li9e thi!:
1de('n#bar#1(n3 ##1(ormat#t#4##-ntering#bar7643 ##1ba*#(n3 ##1(ormat#t#4##Leaving#bar76433
/in#lly the 'unction i! in?o9ed. 7ut 6h#t doe! it *e#n to RETURN-FROM # bloc9 th#t@! !e?er#l l#yer! up on the c#ll !t#c9" &urn! out it 6or9! 'ine--the !t#c9 i! un6ound b#c9 to the 'r#*e 6here the BLOC+ 6#! e!t#bli!hed #nd control return! 'ro* the BLOC+. &he FORMAT e.pre!!ion! in (oo, bar, #nd ba* !ho6 thi!:
$L-+,-./#1(oo3 -ntering#(oo #-ntering#LL;$M ##-ntering#bar ###-ntering#ba* Leaving#(oo 89L
:ote th#t the only H e#?ing . . .H *e!!#ge th#t print! i! the one th#t #ppe#r! #'ter the BLOC+ in (oo. 7ec#u!e the n#*e! o' bloc9! #re le.ic#lly !coped, # RETURN-FROM #l6#y! return! 'ro* the !*#lle!t enclo!ing BLOC+ in the le.ic#l en?iron*ent 6here the RETURN-FROM 'or* #ppe#r! e?en i' the RETURN-FROM i! e.ecuted in # di''erent dyn#*ic conte.t. /or in!t#nce, bar could #l!o cont#in # BLOC+ n#*ed a, li9e thi!:
1de('n#bar#1(n3 ##1(ormat#t#4##-ntering#bar7643 ##1bloc&#a#1ba*#(n33 ##1(ormat#t#4##Leaving#bar76433
&hi! e.tr# BLOC+ 6on@t ch#nge the beh#?ior o' (oo #t #ll--the n#*e a i! re!ol?ed le.ic#lly, #t co*pile ti*e, not dyn#*ic#lly, !o the inter?ening bloc9 h#! no e''ect on the RETURN-FROM. Con?er!ely, the n#*e o' # BLOC+ c#n be u!ed only by RETURN-FROM! #ppe#ring 6ithin the le.ic#l !cope o' the BLOC+G there@! no 6#y 'or code out!ide the bloc9 to return 'ro* the bloc9 e.cept by in?o9ing # clo!ure th#t clo!e! o?er # RETURN-FROM 'ro* the le.ic#l !cope o' the BLOC+. TAGBODY #nd GO 6or9 the !#*e 6#y, in thi! reg#rd, #! BLOC+ #nd RETURN-FROM. When you in?o9e # clo!ure th#t cont#in! # GO 'or*, i' the GO i! e?#lu#ted, the !t#c9 6ill un6ind b#c9 to the #ppropri#te TAGBODY #nd then <u*p to the !peci'ied t#g. BLOC+ n#*e! #nd TAGBODY t#g!, ho6e?er, di''er 'ro* le.ic#l ?#ri#ble binding! in one i*port#nt 6#y. %! I di!cu!!ed in Ch#pter 0, le.ic#l binding! h#?e inde'inite e.tent, *e#ning the binding! c#n !tic9 #round e?en #'ter the binding 'or* h#! returned. BLOC+! #nd TAGBODY!, on the other h#nd, h#?e dyn#*ic e.tent--you c#n RETURN-FROM # BLOC+ or GO to # TAGBODY t#g only 6hile the BLOC+ or TAGBODY i! on the c#ll !t#c9. In other 6ord!, # clo!ure th#t c#pture! # bloc9 n#*e or TAGBODY t#g c#n be p#!!ed down the !t#c9 to be in?o9ed l#ter, but it c#n@t be returned up the !t#c9. I' you in?o9e # clo!ure th#t trie! to RETURN-FROM # BLOC+, #'ter the BLOC+ it!el' h#! returned, you@ll get #n error. i9e6i!e, trying to GO to # TAGBODY th#t no longer e.i!t! 6ill c#u!e #n error.2 It@! unli9ely you@ll need to u!e BLOC+ #nd TAGBODY your!el' 'or thi! 9ind o' !t#c9 un6inding. 7ut you@ll li9ely be u!ing the* indirectly 6hene?er you u!e the condition !y!te*, !o under!t#nding ho6 they 6or9 !hould help you under!t#nd better 6h#t e.#ctly, 'or in!t#nce, in?o9ing # re!t#rt i! doing., CATCH #nd THROW #re #nother p#ir o' !peci#l oper#tor! th#t c#n 'orce the !t#c9 to un6ind. 4ou@ll u!e
the!e oper#tor! e?en le!! o'ten th#n the other! *entioned !o '#r--they@re holdo?er! 'ro* e#rlier i!p di#lect! th#t didn@t h#?e Co**on i!p@! condition !y!te*. &hey de'initely !houldn@t be con'u!ed 6ith tr?;catch #nd tr?;e)cept con!truct! 'ro* l#ngu#ge! !uch #! D#?# #nd Python. CATCH #nd THROW #re the dyn#*ic counterp#rt! o' BLOC+ #nd RETURN-FROM. &h#t i!, you 6r#p CATCH #round # body o' code #nd then u!e THROW to c#u!e the CATCH 'or* to return i**edi#tely 6ith # !peci'ied ?#lue. &he di''erence i! th#t the #!!oci#tion bet6een # CATCH #nd THROW i! e!t#bli!hed dyn#*ic#lly--in!te#d o' # le.ic#lly !coped n#*e, the l#bel 'or # CATCH i! #n ob<ect, c#lled # catch tag, #nd #ny THROW e?#lu#ted 6ithin the dyn#*ic e.tent o' the CATCH th#t thro6! th#t ob<ect 6ill un6ind the !t#c9 b#c9 to the CATCH 'or* #nd c#u!e it to return i**edi#tely. &hu!, you c#n 6rite # ?er!ion o' the (oo, bar, #nd ba* 'unction! 'ro* be'ore u!ing CATCH #nd THROW in!te#d o' BLOC+ #nd RETURN-FROM li9e thi!:
1de(parameter#UobjU#1cons#nil#nil33#S#i.e.#some#arbitrar?#object 1de('n#(oo#13 ##1(ormat#t#4-ntering#(oo7643 ##1catch#UobjU ####1(ormat#t#4#-ntering#$IF$:7643 ####1bar3 ####1(ormat#t#4#Leaving#$IF$:76433 ##1(ormat#t#4Leaving#(oo76433 1de('n#bar#13 ##1(ormat#t#4##-ntering#bar7643 ##1ba*3 ##1(ormat#t#4##Leaving#bar76433 1de('n#ba*#13 ##1(ormat#t#4###-ntering#ba*7643 ##1throw#UobjU#nil3 ##1(ormat#t#4###Leaving#ba*76433
:otice ho6 it i!n@t nece!!#ry to p#!! # clo!ure do6n the !t#c9--ba* c#n c#ll THROW directly. &he re!ult i! Fuite !i*il#r to the e#rlier ?er!ion.
$L-+,-./#1(oo3 -ntering#(oo #-ntering#$IF$: ##-ntering#bar ###-ntering#ba* Leaving#(oo 89L
>o6e?er, CATCH #nd THROW #re #l*o!t too dyn#*ic. In both the CATCH #nd the THROW, the t#g 'or* i! e?#lu#ted, 6hich *e#n! their ?#lue! #re both deter*ined #t runti*e. &hu!, i' !o*e code in bar# re#!!igned or rebound UobjU, the THROW in ba* 6ouldn@t thro6 to the !#*e CATCH. &hi! *#9e! CATCH #nd THROW *uch h#rder to re#!on #bout th#n BLOC+ #nd RETURN-FROM. &he only #d?#nt#ge, 6hich the ?er!ion o' (oo, bar, #nd ba* th#t u!e CATCH #nd THROW de*on!tr#te!, i! there@! no need to p#!! do6n # clo!ure in order 'or lo6-le?el code to return 'ro* # CATCH--#ny code th#t run! 6ithin the dyn#*ic e.tent o' # CATCH c#n c#u!e it to return by thro6ing the right ob<ect. In older i!p di#lect! th#t didn@t h#?e #nything li9e Co**on i!p@! condition !y!te*, CATCH #nd THROW 6ere u!ed 'or error h#ndling. >o6e?er, to 9eep the* *#n#ge#ble, the c#tch t#g! 6ere u!u#lly <u!t Fuoted !y*bol!, !o you could tell by loo9ing #t # CATCH #nd # THROW 6hether they 6ould hoo9
up #t runti*e. In Co**on i!p you@ll r#rely h#?e #ny c#ll to u!e CATCH #nd THROW !ince the condition !y!te* i! !o *uch *ore 'le.ible. &he l#!t !peci#l oper#tor rel#ted to controlling the !t#c9 i! #nother one I@?e *entioned in p#!!ing be'ore--UNWIND-PROTECT. UNWIND-PROTECT let! you control 6h#t h#ppen! #! the !t#c9 un6ind!--to *#9e !ure th#t cert#in code #l6#y! run! reg#rdle!! o' ho6 control le#?e! the !cope o' the UNWIND-PROTECT, 6hether by # nor*#l return, by # re!t#rt being in?o9ed, or by #ny o' the 6#y! di!cu!!ed in thi! !ection.) &he b#!ic !9eleton o' UNWIND-PROTECT loo9! li9e thi!:
1'nwind-protect#protected-form ##cleanup-formU3
&he !ingle protected)form i! e?#lu#ted, #nd then, reg#rdle!! o' ho6 it return!, the cleanup)forms #re e?#lu#ted. I' the protected)form return! nor*#lly, then 6h#te?er it return! i! returned 'ro* the UNWIND-PROTECT #'ter the cle#nup 'or*! run. &he cle#nup 'or*! #re e?#lu#ted in the !#*e dyn#*ic en?iron*ent #! the UNWIND-PROTECT, !o the !#*e dyn#*ic ?#ri#ble binding!, re!t#rt!, #nd condition h#ndler! 6ill be ?i!ible to code in cle#nup 'or*! #! 6ere ?i!ible <u!t be'ore the UNWINDPROTECT. 4ou@ll occ#!ion#lly u!e UNWIND-PROTECT directly. 3ore o'ten you@ll u!e it #! the b#!i! 'or W9F:!tyle *#cro!, !i*il#r to WITH-OPEN-FILE, th#t e?#lu#te #ny nu*ber o' body 'or*! in # conte.t 6here they h#?e #cce!! to !o*e re!ource th#t need! to be cle#ned up #'ter they@re done, reg#rdle!! o' 6hether they return nor*#lly or b#il ?i# # re!t#rt or other nonloc#l e.it. /or e.#*ple, i' you 6ere 6riting # d#t#b#!e libr#ry th#t de'ined 'unction! open-connection #nd close-connection, you *ight 6rite # *#cro li9e thi!:10
1de(macro#with-database-connection#11var#>rest#open-args3#>bod?#bod?3 ##B1let#115var#1open-connection#5Popen-args333 ####1'nwind-protect#1progn#5Pbod?3 ######1close-connection#5var3333
#nd not h#?e to 6orry #bout clo!ing the d#t#b#!e connection, !ince the UNWIND-PROTECT 6ill *#9e !ure it get! clo!ed no *#tter 6h#t h#ppen! in the body o' the with-database-connection 'or*.
+u%tip%e <a%ues
%nother 'e#ture o' Co**on i!p th#t I@?e *entioned in p#!!ing--in Ch#pter 11, 6hen I di!cu!!ed GETHASH--i! the #bility 'or # !ingle 'or* to return *ultiple ?#lue!. I@ll di!cu!! it in gre#ter det#il no6. It i!, ho6e?er, !lightly *i!pl#ced in # ch#pter on !peci#l oper#tor! !ince the #bility to return *ultiple ?#lue! i!n@t pro?ided by <u!t one or t6o !peci#l oper#tor! but i! deeply integr#ted into the l#ngu#ge. &he oper#tor! you@ll *o!t o'ten u!e 6hen de#ling 6ith *ultiple ?#lue! #re *#cro! #nd 'unction!, not !peci#l oper#tor!. 7ut it i! the c#!e th#t the b#!ic #bility to get #t *ultiple return ?#lue! i! pro?ided by # !peci#l oper#tor, MULTIPLE-VALUE-CALL, upon 6hich the *ore co**only u!ed MULTIPLE-VALUEBIND *#cro i! built. &he 9ey thing to under!t#nd #bout *ultiple ?#lue! i! th#t returning *ultiple ?#lue! i! Fuite di''erent 'ro* returning # li!t--i' # 'or* return! *ultiple ?#lue!, unle!! you do !o*ething !peci'ic to c#pture the
*ultiple ?#lue!, #ll but the primar0 value 6ill be !ilently di!c#rded. &o !ee the di!tinction, con!ider the 'unction GETHASH, 6hich return! t6o ?#lue!: the ?#lue 'ound in the h#!h t#ble #nd # boole#n th#t@! NIL 6hen no ?#lue 6#! 'ound. I' it returned tho!e t6o ?#lue! in # li!t, e?ery ti*e you c#lled GETHASH you@d h#?e to t#9e #p#rt the li!t to get #t the #ctu#l ?#lue, reg#rdle!! o' 6hether you c#red #bout the !econd return ?#lue. Suppo!e you h#?e # h#!h t#ble, UhU, th#t cont#in! nu*eric ?#lue!. I' GETHASH returned # li!t, you couldn@t 6rite !o*ething li9e thi!:
12#1gethash#Ca#UhU3#1gethash#Cb#UhU33
bec#u!e + e.pect! it! #rgu*ent! to be nu*ber!, not li!t!. 7ut bec#u!e the *ultiple ?#lue *ech#ni!* !ilently di!c#rd! the !econd#ry return ?#lue 6hen it@! not 6#nted, thi! 'or* 6or9! 'ine. &here #re t6o #!pect! to u!ing *ultiple ?#lue!--returning *ultiple ?#lue! #nd getting #t the nonpri*#ry ?#lue! returned by 'or*! th#t return *ultiple ?#lue!. &he !t#rting point! 'or returning *ultiple ?#lue! #re the 'unction! VALUES #nd VALUES-LIST. &he!e #re regul#r 'unction!, not !peci#l oper#tor!, !o their #rgu*ent! #re p#!!ed in the nor*#l 6#y. VALUES t#9e! # ?#ri#ble nu*ber o' #rgu*ent! #nd return! the* #! *ultiple ?#lue!G VALUES-LIST t#9e! # !ingle li!t #nd return! it! ele*ent! #! *ultiple ?#lue!. In other 6ord!:
1val'es-list#)3#===#1appl?#NCval'es#)3
&he *ech#ni!* by 6hich *ultiple ?#lue! #re returned i! i*ple*ent#tion dependent <u!t li9e the *ech#ni!* 'or p#!!ing #rgu*ent! into 'unction! i!. %l*o!t #ll l#ngu#ge con!truct! th#t return the ?#lue o' !o*e !ub'or* 6ill Hp#!! throughH *ultiple ?#lue!, returning #ll the ?#lue! returned by the !ub'or*. &hu!, # 'unction th#t return! the re!ult o' c#lling VALUES or VALUES-LIST 6ill it!el' return *ultiple ?#lue!--#nd !o 6ill #nother 'unction 6ho!e re!ult co*e! 'ro* c#lling the 'ir!t 'unction. %nd !o on.11 7ut 6hen # 'or* i! e?#lu#ted in # ?#lue po!ition, only the pri*#ry ?#lue 6ill be u!ed, 6hich i! 6hy the pre?iou! #ddition 'or* 6or9! the 6#y you@d e.pect. &he !peci#l oper#tor MULTIPLE-VALUE-CALL pro?ide! the *ech#ni!* 'or getting your h#nd! on the *ultiple ?#lue! returned by # 'or*. MULTIPLE-VALUE-CALL i! !i*il#r to FUNCALL e.cept th#t 6hile FUNCALL i! # regul#r 'unction #nd, there'ore, c#n !ee #nd p#!! on only the pri*#ry ?#lue! p#!!ed to it, MULTIPLE-VALUE-CALL p#!!e!, to the 'unction returned by it! 'ir!t !ub'or*, all the ?#lue! returned by the re*#ining !ub'or*!.
1('ncall#NC2#1val'es#0#!3#1val'es#3#433#############==/#4 1m'ltiple-val'e-call#NC2#1val'es#0#!3#1val'es#3#433#==/#0
>o6e?er, it@! '#irly r#re th#t you@ll !i*ply 6#nt to p#!! #ll the ?#lue! returned by # 'unction onto #nother 'unction. 3ore li9ely, you@ll 6#nt to !t#!h the *ultiple ?#lue! in di''erent ?#ri#ble! #nd then do !o*ething 6ith the*. &he MULTIPLE-VALUE-BIND *#cro, 6hich you !#6 in Ch#pter 11, i! the *o!t 'reFuently u!ed oper#tor 'or #ccepting *ultiple return ?#lue!. It! !9eleton loo9! li9e thi!:
1m'ltiple-val'e-bind#1variableU3#values-form ##body-formU3
&he values)form i! e?#lu#ted, #nd the *ultiple ?#lue! it return! #re bound to the variables. &hen the bod0)forms #re e?#lu#ted 6ith tho!e binding! in e''ect. &hu!:
1m'ltiple-val'e-bind#1)#?3#1val'es#0#!3 ##12#)#?33#==/#3
%nother *#cro, MULTIPLE-VALUE-LIST, i! e?en !i*pler--it t#9e! # !ingle 'or*, e?#lu#te! it, #nd collect! the re!ulting *ultiple ?#lue! into # li!t. In other 6ord!, it@! the in?er!e o' VALUES-LIST.
>o6e?er, i' you 'ind your!el' u!ing MULTIPLE-VALUE-LIST # lot, it *#y be # !ign th#t !o*e 'unction !hould be returning # li!t to !t#rt 6ith r#ther th#n *ultiple ?#lue!. /in#lly, i' you 6#nt to #!!ign *ultiple ?#lue! returned by # 'or* to e.i!ting ?#ri#ble!, you c#n u!e VALUES #! # SETF#ble pl#ce. /or e.#*ple:
$L-+,-./#1de(parameter#U)U#nil3 U[U $L-+,-./#1de(parameter#U?U#nil3 UHU $L-+,-./#1set(#1val'es#U)U#U?U3#1(loor#1/#"Q#34333 0 !3/34 $L-+,-./#U)U 0 $L-+,-./#U?U !3/34
!<AL4W.!:
% !peci#l oper#tor you@ll need to under!t#nd in order to 6rite cert#in 9ind! o' *#cro! i! EVAL-WHEN. /or !o*e re#!on, i!p boo9! o'ten tre#t EVAL-WHEN #! # 6iA#rd!-only topic. 7ut the only prereFui!ite to under!t#nding EVAL-WHEN i! #n under!t#nding o' ho6 the t6o 'unction! LOAD #nd COMPILEFILE inter#ct. %nd under!t#nding EVAL-WHEN 6ill be i*port#nt #! you !t#rt 6riting cert#in 9ind! o' *ore !ophi!tic#ted *#cro!, !uch #! the one! you@ll 6rite in Ch#pter! 2- #nd 31. I@?e touched brie'ly on the rel#tion bet6een LOAD #nd COMPILE-FILE in pre?iou! ch#pter!, but it@! 6orth re?ie6ing #g#in here. &he <ob o' LOAD i! to lo#d # 'ile #nd e?#lu#te #ll the top-le?el 'or*! it cont#in!. &he <ob o' COMPILE-FILE i! to co*pile # !ource 'ile into # /%S 'ile, 6hich c#n then be lo#ded 6ith LOAD !uch th#t 1load#4(oo.lisp43 #nd 1load#4(oo.(asl43 #re e!!enti#lly eFui?#lent. 7ec#u!e LOAD e?#lu#te! e#ch 'or* be'ore re#ding the ne.t, the !ide e''ect! o' e?#lu#ting 'or*! e#rlier in the 'ile c#n #''ect ho6 'or*! l#ter in the 'or* #re re#d #nd e?#lu#ted. /or in!t#nce, e?#lu#ting #n IN-PAC+AGE 'or* ch#nge! the ?#lue o' *PAC+AGE*, 6hich 6ill #''ect the 6#y !ub!eFuent 'or*! #re re#d.12 Si*il#rly, # DEFMACRO 'or* e#rly in # 'ile c#n de'ine # *#cro th#t c#n then be u!ed by code l#ter in the 'ile.13 COMPILE-FILE, on the other h#nd, nor*#lly doe!n@t e?#lu#te the 'or*! it@! co*pilingG it@! 6hen the /%S i! lo#ded th#t the 'or*!--or their co*piled eFui?#lent!--6ill be e?#lu#ted. >o6e?er, COMPILEFILE *u!t e?#lu#te !o*e 'or*!, !uch #! IN-PAC+AGE #nd DEFMACRO 'or*!, in order to 9eep the beh#?ior o' 1load#4(oo.lisp43 #nd 1load#4(oo.(asl43 con!i!tent. So ho6 do *#cro! !uch #! IN-PAC+AGE #nd DEFMACRO 6or9 6hen proce!!ed by COMPILEFILE" In !o*e pre-Co**on i!p ?er!ion! o' i!p, the 'ile co*piler !i*ply 9ne6 it !hould e?#lu#te cert#in *#cro! in #ddition to co*piling the*. Co**on i!p #?oided the need 'or !uch 9ludge! by borro6ing the EVAL-WHEN !peci#l oper#tor 'ro* 3#cli!p. &hi! oper#tor, #! it! n#*e !ugge!t!, #llo6!
you to control 6hen !peci'ic bit! o' code #re e?#lu#ted. &he !9eleton o' #n EVAL-WHEN 'or* loo9! li9e thi!:
1eval-when#1situationU3 ##body-formU3
&here #re three po!!ible situations--:compile-toplevel, :load-toplevel, #nd :e)ec'te-#nd 6hich one! you !peci'y control! 6hen the bod0)forms 6ill be e?#lu#ted. %n EVAL-WHEN 6ith *ultiple !itu#tion! i! eFui?#lent to !e?er#l EVAL-WHEN 'or*!, one per !itu#tion, e#ch 6ith the !#*e body code. &o e.pl#in the *e#ning o' the three !itu#tion!, I@ll need to e.pl#in # bit #bout ho6 COMPILE-FILE, 6hich i! #l!o re'erred to #! the file compiler, goe! #bout co*piling # 'ile. &o e.pl#in ho6 COMPILE-FILE co*pile! EVAL-WHEN 'or*!, I need to introduce # di!tinction bet6een co*piling top)level 'or*! #nd co*piling non-top-le?el 'or*!. % top-le?el 'or* i!, roughly !pe#9ing, one th#t 6ill be co*piled into code th#t 6ill be run 6hen the /%S i! lo#ded. &hu!, #ll 'or*! th#t #ppe#r directly #t the top le?el o' # !ource 'ile #re co*piled #! top-le?el 'or*!. Si*il#rly, #ny 'or*! #ppe#ring directly in # top-le?el PROGN #re co*piled #! top-le?el 'or*! !ince the PROGN it!el' doe!n@t do #nything--it <u!t group! together it! !ub'or*!, 6hich 6ill be run 6hen the /%S i! lo#ded.1Si*il#rly, 'or*! #ppe#ring directly in # MACROLET or SYMBOL-MACROLET #re co*piled #! top-le?el 'or*! bec#u!e #'ter the co*piler h#! e.p#nded the loc#l *#cro! or !y*bol *#cro!, there 6ill be no re*n#nt o' the MACROLET or SYMBOL-MACROLET in the co*piled code. /in#lly, the e.p#n!ion o' # top-le?el *#cro 'or* 6ill be co*piled #! # top-le?el 'or*. &hu!, # DEFUN #ppe#ring #t the top le?el o' # !ource 'ile i! # top-le?el 'or*--the code th#t de'ine! the 'unction #nd #!!oci#te! it 6ith it! n#*e 6ill run 6hen the /%S i! lo#ded--but the 'or*! 6ithin the body o' the 'unction, 6hich 6on@t run until the 'unction i! c#lled, #ren@t top-le?el 'or*!. 3o!t 'or*! #re co*piled the !#*e 6hen co*piled #! top-le?el #nd non-top-le?el 'or*!, but the !e*#ntic! o' #n EVAL-WHEN depend on 6hether it@! being co*piled #! # top- le?el 'or*, co*piled #! # non-top-le?el 'or*, or !i*ply e?#lu#ted, co*bined 6ith 6h#t !itu#tion! #re li!ted in it! !itu#tion li!t. &he !itu#tion! :compile-toplevel #nd :load-toplevel control the *e#ning o' #n EVALWHEN co*piled #! # top-le?el 'or*. When :compile-toplevel i! pre!ent, the 'ile co*piler 6ill e?#lu#te the !ub'or*! #t co*pile ti*e. When :load-toplevel i! pre!ent, it 6ill co*pile the !ub'or*! #! top-le?el 'or*!. I' neither o' the!e !itu#tion! i! pre!ent in # top-le?el EVAL-WHEN, the co*piler ignore! it. When #n EVAL-WHEN i! co*piled #! # non-top-le?el 'or*, it@! either co*piled li9e # PROGN, i' the :e)ec'te !itu#tion i! !peci'ied, or ignored. Si*il#rly, #n e?#lu#ted EVAL-WHEN--6hich include! top-le?el EVAL-WHEN! in # !ource 'ile proce!!ed by LOAD #nd EVAL-WHEN! e?#lu#ted #t co*pile ti*e bec#u!e they #ppe#r #! !ub'or*! o' # top-le?el EVAL-WHEN 6ith the :compile-toplevel !itu#tion--i! tre#ted li9e # PROGN i' :e)ec'te i! pre!ent #nd ignored other6i!e. &hu!, # *#cro !uch #! IN-PAC+AGE c#n h#?e the nece!!#ry e''ect #t both co*pile ti*e #nd 6hen lo#ding 'ro* !ource by e.p#nding into #n EVAL-WHEN li9e the 'ollo6ing:
1eval-when#1:compile-toplevel#:load-toplevel#:e)ec'te3 ##1set(#Upac&ageU#1(ind-pac&age#4TI$MIJ--8I%-4333
*PAC+AGE* 6ill be !et #t co*pile ti*e bec#u!e o' the :compile-toplevel !itu#tion, !et 6hen the /%S i! lo#ded bec#u!e o' :load-toplevel, #nd !et 6hen the !ource i! lo#ded bec#u!e o' the :e)ec'te. &here #re t6o 6#y! you@re *o!t li9ely to u!e EVAL-WHEN. 5ne i! i' you 6#nt to 6rite *#cro! th#t
need to !#?e !o*e in'or*#tion #t co*pile ti*e to be u!ed 6hen gener#ting the e.p#n!ion o' other *#cro 'or*! in the !#*e 'ile. &hi! typic#lly #ri!e! 6ith de'inition#l *#cro! 6here # de'inition e#rly in # 'ile c#n #''ect the code gener#ted 'or # de'inition l#ter in the !#*e 'ile. 4ou@ll 6rite thi! 9ind o' *#cro in Ch#pter 2-. &he other ti*e you *ight need EVAL-WHEN i! i' you 6#nt to put the de'inition o' # *#cro #nd helper 'unction! it u!e! in the !#*e 'ile #! code th#t u!e! the *#cro. DEFMACRO #lre#dy include! #n EVALWHEN in it! e.p#n!ion !o the *#cro de'inition i! i**edi#tely #?#il#ble to be u!ed l#ter in the 'ile. 7ut DEFUN nor*#lly doe!n@t *#9e 'unction de'inition! #?#il#ble #t co*pile ti*e. 7ut i' you u!e # *#cro in the !#*e 'ile #! it@! de'ined in, you need the *#cro and #ny 'unction! it u!e! to be de'ined. I' you 6r#p the DEFUN! o' #ny helper 'unction! u!ed by the *#cro in #n EVAL-WHEN 6ith :compiletoplevel, the de'inition! 6ill be #?#il#ble 6hen the *#cro@! e.p#n!ion 'unction run!. 4ou@ll prob#bly 6#nt to include :load-toplevel #nd :e)ec'te #! 6ell !ince the *#cro! 6ill #l!o need the 'unction de'inition! #'ter the 'ile i! co*piled #nd lo#ded or i' you lo#d the !ource in!te#d o' co*piling.
In code not proce!!ed by COMPILE-FILE, LOAD-TIME-VALUE i! e?#lu#ted once 6hen the code i! co*piled, 6hich *#y be 6hen you e.plicitly co*pile # 'unction 6ith COMPILE or e#rlier bec#u!e o' i*plicit co*pil#tion per'or*ed by the i*ple*ent#tion in the cour!e o' e?#lu#ting the code. In unco*piled code, LOAD-TIME-VALUE e?#lu#te! it! 'or* e#ch ti*e it@! e?#lu#ted. /in#lly, PROGV cre#te! ne6 dyn#*ic binding! 'or ?#ri#ble! 6ho!e n#*e! #re deter*ined #t runti*e. &hi! i! *o!tly u!e'ul 'or i*ple*enting e*bedded interpreter! 'or l#ngu#ge! 6ith dyn#*ic#lly !coped ?#ri#ble!. &he b#!ic !9eleton i! #! 'ollo6!:
1progv#symbols-list#values-list ##body-formU3
6here s0mbols)list i! # 'or* th#t e?#lu#te! to # li!t o' !y*bol! #nd values)list i! # 'or* th#t e?#lu#te! to # li!t o' ?#lue!. (#ch !y*bol i! dyn#*ic#lly bound to the corre!ponding ?#lue, #nd then the bod0)forms #re e?#lu#ted. &he di''erence bet6een PROGV #nd LET i! th#t bec#u!e s0mbols)list i! e?#lu#ted #t runti*e, the n#*e! o' the ?#ri#ble! to bind c#n be deter*ined dyn#*ic#lly. %! I !#y, thi! i!n@t !o*ething you need to do o'ten. %nd th#t@! it 'or !peci#l oper#tor!. In the ne.t ch#pter, I@ll get b#c9 to h#rd-no!ed pr#ctic#l topic! #nd !ho6 you ho6 to u!e Co**on i!p@! p#c9#ge !y!te* to t#9e control o' your n#*e!p#ce! !o you c#n 6rite libr#rie! #nd #pplic#tion! th#t c#n coe.i!t 6ithout !to*ping on e#ch other@! n#*e!.
15'
cour!e, i' IF 6#!n@t # !peci#l oper#tor but !o*e other condition#l 'or*, !uch #! COND, 6#!, you could build IF #! # *#cro. Indeed, in *#ny i!p di#lect!, !t#rting 6ith 3cC#rthy@! origin#l i!p, COND 6#! the pri*iti?e condition#l e?#lu#tion oper#tor.
2Well,
technic#lly tho!e con!truct! could #l!o e.p#nd into # LAMBDA e.pre!!ion !ince, #! I *entioned in Ch#pter 0, LET could be de'ined--#nd 6#! in !o*e e#rlier i!p!--#! # *#cro th#t e.p#nd! into #n in?oc#tion o' #n #nony*ou! 'unction.
3Surpri!ing
#! it *#y !ee*, it #ctu#lly i! po!!ible to *#9e #nony*ou! 'unction! recur!e. >o6e?er, you *u!t u!e # r#ther e!oteric *ech#ni!* 9no6n #! the 1 combinator. 7ut the 4 co*bin#tor i! #n intere!ting theoretic#l re!ult, not # pr#ctic#l progr#**ing tool, !o i! 6ell out!ide the !cope o' thi! boo9.
-It@!
not reFuired th#t WITH-SLOTS be i*ple*ented 6ith SYMBOL-MACROLET--in !o*e i*ple*ent#tion!, WITH-SLOTS *#y 6#l9 the code pro?ided #nd gener#te #n e.p#n!ion 6ith ), ?, #nd * #lre#dy repl#ced 6ith the #ppropri#te SLOT-VALUE 'or*!. 4ou c#n !ee ho6 your i*ple*ent#tion doe! it by e?#lu#ting thi! 'or*:
1macroe)pand-0#C1with-slots#1)#?#*3#obj#1list#)#?#*333
>o6e?er, 6#l9ing the body i! *uch e#!ier 'or the i!p i*ple*ent#tion to do th#n 'or u!er codeG to repl#ce ), ?, #nd * only 6hen they #ppe#r in ?#lue po!ition! reFuire! # code 6#l9er th#t under!t#nd! the !ynt#. o' #ll !peci#l oper#tor! #nd th#t recur!i?ely e.p#nd! #ll *#cro 'or*! in order to deter*ine 6hether their e.p#n!ion! include the !y*bol! in ?#lue po!ition!. &he i!p i*ple*ent#tion ob?iou!ly h#! !uch # code 6#l9er #t it! di!po!#l, but it@! one o' the 'e6 p#rt! o' i!p th#t@! not e.po!ed to u!er! o' the l#ngu#ge.
55ne
?er!ion o' '2cl i! #?#il#ble #! p#rt o' the Co**on i!p 5pen Code Collection BC 5CCC: http://clocc.so'rce(orge.net/. 7y contr#!t, con!ider the tric9! the #uthor! o' '2<, # /5$&$%:-to-D#?# tr#n!l#tor, h#?e to pl#y. %lthough the D#?# 1irtu#l 3#chine BD13C h#! # goto in!truction, it@! not directly e.po!ed in D#?#. So to co*pile /5$&$%: goto!, they 'ir!t co*pile the /5$&$%: code into leg#l D#?# !ource 6ith c#ll! to # du**y cl#!! to repre!ent the l#bel! #nd goto!. &hen they co*pile the !ource 6ith # regul#r D#?# co*piler #nd po!tproce!! the byte code! to tr#n!l#te the du**y c#ll! into D13-le?el byte code!. Cle?er, but 6h#t # p#in.
0Since
thi! #lgorith* depend! on ?#lue! returned by RANDOM, you *#y 6#nt to te!t it 6ith # con!i!tent r#ndo* !eed, 6hich you c#n get by binding *RANDOM-STATE* to the ?#lue o' 1ma&e-randomstate#nil3 #round e#ch c#ll to algorithm-s. /or in!t#nce, you c#n do # b#!ic !#nity chec9 o' algorithm-s by e?#lu#ting thi!:
1let#11Urandom-stateU#1ma&e-random-state#nil333#1algorithm-s#0 #! 33
I' your re'#ctoring! #re #ll ?#lid, thi! e.pre!!ion !hould e?#lu#te to the !#*e li!t e#ch ti*e.
2&hi!
i! # pretty re#!on#ble re!triction--it@! not entirely cle#r 6h#t it@d *e#n to return 'ro* # 'or* th#t h#! #lre#dy returned--unle!!, o' cour!e, you@re # Sche*e progr#**er. Sche*e !upport! continuations, # l#ngu#ge con!truct th#t *#9e! it po!!ible to return 'ro* the !#*e 'unction c#ll *ore th#n once. 7ut 'or # ?#riety o' re#!on!, 'e6, i' #ny, l#ngu#ge! other th#n Sche*e !upport thi! 9ind o' continu#tion.
,I'
you@re the 9ind o' per!on 6ho li9e! to 9no6 ho6 thing! 6or9 #ll the 6#y do6n to the bit!, it *#y be in!tructi?e to thin9 #bout ho6 you *ight i*ple*ent the condition !y!te*@! *#cro! u!ing BLOC+, TAGBODY, clo!ure!, #nd dyn#*ic ?#ri#ble!.
)UNWIND-PROTECT 10%nd
indeed, C SM , the *ulti- i!p, *ultid#t#b#!e SM inter'#ce libr#ry, pro?ide! # !i*il#r *#cro c#lled with-database. C SM @! ho*e p#ge i! #t http://[email protected].
11% !*#ll
h#nd'ul o' *#cro! don@t p#!! through e.tr# return ?#lue! o' the 'or*! they e?#lu#te. In p#rticul#r, the PROG1 *#cro, 6hich e?#lu#te! # nu*ber o' 'or*! li9e # PROGN be'ore returning the ?#lue o' the 'ir!t 'or*, return! th#t 'or*@! pri*#ry ?#lue only. i9e6i!e, PROG9, 6hich return! the ?#lue o' the !econd o' it! !ub'or*!, return! only the pri*#ry ?#lue. &he !peci#l oper#tor MULTIPLEVALUE-PROG1 i! # ?#ri#nt o' PROG1 th#t return! #ll the ?#lue! returned by the 'ir!t 'or*. It@! # *inor 6#rt th#t PROG1 doe!n@t #lre#dy beh#?e li9e MULTIPLE-VALUE-PROG1, but neither i! u!ed o'ten enough th#t it *#tter! *uch. &he OR #nd COND *#cro! #re #l!o not #l6#y! tr#n!p#rent to *ultiple ?#lue!, returning only the pri*#ry ?#lue o' cert#in !ub'or*!.
12&he
re#!on lo#ding # 'ile 6ith #n IN-PAC+AGE 'or* in it h#! no e''ect on the ?#lue o' *PAC+AGE* #'ter LOAD return! i! bec#u!e LOAD bind! *PAC+AGE* to it! current ?#lue be'ore doing #nything el!e. In other 6ord!, !o*ething eFui?#lent to the 'ollo6ing LET i! 6r#pped #round the re!t o' the code in LOAD:
1let#11Upac&ageU#Upac&ageU33#...3
%ny #!!ign*ent to *PAC+AGE* 6ill be to the ne6 binding, #nd the old binding 6ill be re!tored 6hen LOAD return!. It #l!o bind! the ?#ri#ble *READTABLE*, 6hich I h#?en@t di!cu!!ed, in the !#*e 6#y.
13In
!o*e i*ple*ent#tion!, you *#y be #ble to get #6#y 6ith e?#lu#ting DEFUN! th#t u!e unde'ined *#cro! in the 'unction body #! long #! the *#cro! #re de'ined be'ore the 'unction i! #ctu#lly c#lled. 7ut th#t 6or9!, i' #t #ll, only 6hen LOADing the de'inition! 'ro* !ource, not 6hen co*piling 6ith COMPILE-FILE, !o in gener#l *#cro de'inition! *u!t be e?#lu#ted be'ore they@re u!ed.
1-7y contr#!t,
the !ub'or*! in # top-le?el LET #ren@t co*piled #! top-le?el 'or*! bec#u!e they@re not run directly 6hen the /%S i! lo#ded. &hey 6ill run, but it@! in the runti*e conte.t o' the binding! e!t#bli!hed by the LET. &heoretic#lly, # LET th#t bind! no ?#ri#ble! could be tre#ted li9e # PROGN, but it@! not--the 'or*! #ppe#ring in # LET #re ne?er tre#ted #! top-le?el 'or*!.
15&he
one decl#r#tion th#t h#! #n e''ect on the !e*#ntic! o' # progr#* i! the SPECIAL decl#r#tion *entioned in Ch#pter 0.
libr#ry in order to #?oid con'lict! bet6een tho!e n#*e! #nd the n#*e! you u!e in your progr#*. 4ou@d li9e 'or *o!t o' the n#*e! in the libr#ry #nd the n#*e! in your progr#* to be con!idered di!tinct e?en i' they h#ppen to h#?e the !#*e te.tu#l repre!ent#tion. %t the !#*e ti*e, you@d li9e cert#in n#*e! de'ined in the libr#ry to be re#dily #cce!!ible--the n#*e! th#t *#9e up it! public %PI, 6hich you@ll 6#nt to u!e in your progr#*. In Co**on i!p, thi! n#*e!p#ce proble* boil! do6n to # Fue!tion o' controlling ho6 the re#der tr#n!l#te! te.tu#l n#*e! into !y*bol!: i' you 6#nt t6o occurrence! o' the !#*e n#*e to be con!idered the !#*e by the e?#lu#tor, you need to *#9e !ure the re#der u!e! the !#*e !y*bol to repre!ent e#ch n#*e. Con?er!ely, i' you 6#nt t6o n#*e! to be con!idered di!tinct, e?en i' they h#ppen to h#?e the !#*e te.tu#l n#*e, you need the re#der to cre#te di''erent !y*bol! to repre!ent e#ch n#*e.
p#c9#ge #uthor 6ill neglect to e.port # !y*bol th#t re#lly ought to be public. In th#t c#!e, # doublecolon n#*e let! you get 6or9 done 6ithout h#?ing to 6#it 'or the ne.t ?er!ion o' the p#c9#ge to be rele#!ed. &6o other bit! o' !y*bol !ynt#. the re#der under!t#nd! #re tho!e 'or 9ey6ord !y*bol! #nd uninterned !y*bol!. Ley6ord !y*bol! #re 6ritten 6ith n#*e! !t#rting 6ith # colon. Such !y*bol! #re interned in the p#c9#ge n#*ed +EYWORD #nd #uto*#tic#lly e.ported. %ddition#lly, 6hen the re#der intern! # !y*bol in the +EYWORD, it #l!o de'ine! # con!t#nt ?#ri#ble 6ith the !y*bol #! both it! n#*e #nd ?#lue. &hi! i! 6hy you c#n u!e 9ey6ord! in #rgu*ent li!t! 6ithout Fuoting the*--6hen they #ppe#r in # ?#lue po!ition, they e?#lu#te to the*!el?e!. &hu!:
1e@l#C:(oo#:(oo3#==/#F
&he n#*e! o' 9ey6ord !y*bol!, li9e #ll !y*bol!, #re con?erted to #ll upperc#!e by the re#der be'ore they@re interned. &he n#*e doe!n@t include the le#ding colon.
1s?mbol-name#:(oo3#==/#4E;;4
8ninterned !y*bol! #re 6ritten 6ith # le#ding N:. &he!e n#*e! B*inu! the N:C #re con?erted to upperc#!e #! nor*#l #nd then tr#n!l#ted into !y*bol!, but the !y*bol! #ren@t interned in #ny p#c9#geG e#ch ti*e the re#der re#d! # N: n#*e, it cre#te! # ne6 !y*bol. &hu!:
1e@l#CN:(oo#CN:(oo3#==/#89L
4ou@ll r#rely, i' e?er, 6rite thi! !ynt#. your!el', but 6ill !o*eti*e! !ee it 6hen you print #n !e.pre!!ion cont#ining !y*bol! returned by the 'unction GENSYM.
1gens?m3#==/#N:J30!R
!y*bol #nd #n inherited !y*bol 6ith the !#*e n#*e or inherit t6o di''erent !y*bol!, 'ro* di''erent p#c9#ge!, 6ith the !#*e n#*e. >o6e?er, you c#n re!ol?e con'lict! by *#9ing one o' the #cce!!ible !y*bol! # shadowing !y*bol, 6hich *#9e! the other !y*bol! o' the !#*e n#*e in#cce!!ible. In #ddition to it! n#*e-to-!y*bol t#ble, e#ch p#c9#ge *#int#in! # li!t o' !h#do6ing !y*bol!. %n e.i!ting !y*bol c#n be imported into #nother p#c9#ge by #dding it to the p#c9#ge@! n#*e-to-!y*bol t#ble. &hu!, the !#*e !y*bol c#n be pre!ent in *ultiple p#c9#ge!. So*eti*e! you@ll i*port !y*bol! !i*ply bec#u!e you 6#nt the* to be #cce!!ible in the i*porting p#c9#ge 6ithout u!ing their ho*e p#c9#ge. 5ther ti*e! you@ll i*port # !y*bol bec#u!e only pre!ent !y*bol! c#n be e.ported or be !h#do6ing !y*bol!. /or in!t#nce, i' # p#c9#ge need! to u!e t6o p#c9#ge! th#t h#?e e.tern#l !y*bol! o' the !#*e n#*e, one o' the !y*bol! *u!t be i*ported into the u!ing p#c9#ge in order to be #dded to it! !h#do6ing li!t #nd *#9e the other !y*bol in#cce!!ible. /in#lly, # pre!ent !y*bol c#n be uninterned 'ro* # p#c9#ge, 6hich c#u!e! it to be re*o?ed 'ro* the n#*e-to-!y*bol t#ble #nd, i' it@! # !h#do6ing !y*bol, 'ro* the !h#do6ing li!t. 4ou *ight unintern # !y*bol 'ro* # p#c9#ge to re!ol?e # con'lict bet6een the !y*bol #nd #n e.tern#l !y*bol 'ro* # p#c9#ge you 6#nt to u!e. % !y*bol th#t i!n@t pre!ent in #ny p#c9#ge i! c#lled #n uninterned !y*bol, c#n no longer be re#d by the re#der, #nd 6ill be printed u!ing the N:(oo !ynt#..
the re#der re#d! DEFVAR #! the !y*bol 'ro* the $;%%;8-L9,T p#c9#ge #nd U[U #! # !y*bol in $;%%;8-L9,T-+,-.. &he $(P c#n@t !t#rt in the $;%%;8-L9,T p#c9#ge bec#u!e you@re not #llo6ed to intern ne6 !y*bol!
in itG $;%%;8-L9,T-+,-. !er?e! #! # H!cr#tchH p#c9#ge 6here you c#n cre#te your o6n n#*e! 6hile !till h#?ing e#!y #cce!! to #ll the !y*bol! in $;%%;8-L9,T.3 &ypic#lly, #ll p#c9#ge! you@ll de'ine 6ill #l!o u!e $;%%;8-L9,T, !o you don@t h#?e to 6rite thing! li9e thi!:
1cl:de('n#1)3#1cl:2#)#!33
&he third !t#nd#rd p#c9#ge i! the +EYWORD p#c9#ge, the p#c9#ge the i!p re#der u!e! to intern n#*e! !t#rting 6ith colon. &hu!, you c#n #l!o re'er to #ny 9ey6ord !y*bol 6ith #n e.plicit p#c9#ge Fu#li'ic#tion o' &e?word li9e thi!:
$L-+,-./#:a :I $L-+,-./#&e?word:a :I $L-+,-./#1e@l#:a#&e?word:a3 F
&hi! de'ine! # p#c9#ge, n#*ed $;%.J9JI%;8M-H,.-%I9L-<L, th#t inherit! #ll the !y*bol! e.ported by the $;%%;8-L9,T p#c9#ge.0 4ou #ctu#lly h#?e !e?er#l choice! o' ho6 to repre!ent the n#*e! o' p#c9#ge! #nd, #! you@ll !ee, the n#*e! o' !y*bol! in # DEFPAC+AGE. P#c9#ge! #nd !y*bol! #re n#*ed 6ith !tring!. >o6e?er, in # DEFPAC+AGE 'or*, you c#n !peci'y the n#*e! o' p#c9#ge! #nd !y*bol! 6ith string designators. % !tring de!ign#tor i! either # !tring, 6hich de!ign#te! it!el'G # !y*bol, 6hich de!ign#te! it! n#*eG or # ch#r#cter, 6hich de!ign#te! # one-ch#r#cter !tring cont#ining <u!t the ch#r#cter. 8!ing 9ey6ord !y*bol!, #! in the pre?iou! DEFPAC+AGE, i! # co**on !tyle th#t #llo6! you to 6rite the n#*e! in lo6erc#!e--the re#der 6ill con?ert the n#*e! to upperc#!e 'or you. 4ou could #l!o 6rite the DEFPAC+AGE 6ith !tring!, but then you h#?e to 6rite the* in #ll upperc#!e, bec#u!e the true n#*e! o' *o!t !y*bol! #nd p#c9#ge! #re in '#ct upperc#!e bec#u!e o' the c#!e con?er!ion per'or*ed by the re#der.2
1de(pac&age#4$;%.J9JI%;8M-H,.-%I9L-<L4 ##1:'se#4$;%%;8-L9,T433
4ou could #l!o u!e non9ey6ord !y*bol!--the n#*e! in DEFPAC+AGE #ren@t e?#lu#ted--but then the ?ery #ct o' re#ding the DEFPAC+AGE 'or* 6ould c#u!e tho!e !y*bol! to be interned in the current p#c9#ge, 6hich #t the ?ery le#!t 6ill pollute th#t n#*e!p#ce #nd *#y #l!o c#u!e proble*! l#ter i' you try to u!e the p#c9#ge., &o re#d code in thi! p#c9#ge, you need to *#9e it the current p#c9#ge 6ith the IN-PAC+AGE *#cro:
1in-pac&age#:com.gigamon&e?s.email-db3
I' you type thi! e.pre!!ion #t the $(P , it 6ill ch#nge the ?#lue o' *PAC+AGE*, #''ecting ho6 the $(P re#d! !ub!eFuent e.pre!!ion!, until you ch#nge it 6ith #nother c#ll to IN-PAC+AGE. Si*il#rly, i' you include #n IN-PAC+AGE in # 'ile th#t@! lo#ded 6ith LOAD or co*piled 6ith COMPILE-FILE, it 6ill ch#nge the p#c9#ge, #''ecting the 6#y !ub!eFuent e.pre!!ion! in the 'ile #re re#d.) With the current p#c9#ge !et to the $;%.J9JI%;8M-H,.-%I9L-<L p#c9#ge, other th#n n#*e! inherited 'ro* the $;%%;8-L9,T p#c9#ge, you c#n u!e #ny n#*e you 6#nt 'or 6h#te?er purpo!e you 6#nt. &hu!, you could de'ine # ne6 hello-world 'unction th#t could coe.i!t 6ith the helloworld 'unction pre?iou!ly de'ined in $;%%;8-L9,T-+,-.. >ere@! the beh#?ior o' the e.i!ting 'unction:
$L-+,-./#1hello-world3 hello5#world 89L
:o6 you c#n !6itch to the ne6 p#c9#ge u!ing IN-PAC+AGE.10 :otice ho6 the pro*pt ch#nge!--the e.#ct 'or* i! deter*ined by the de?elop*ent en?iron*ent, but in S I3( the de'#ult pro*pt con!i!t! o' #n #bbre?i#ted ?er!ion o' the p#c9#ge n#*e.
$L-+,-./#1in-pac&age#:com.gigamon&e?s.email-db3 NOFhe#$;%.J9JI%;8M-H,.-%I9L-<L#pac&age/ -%I9L-<L/#
%g#in, you u!e the $;%%;8-L9,T p#c9#ge, bec#u!e you@ll need #cce!! to !t#nd#rd 'unction! 6ithin $;%.J9JI%;8M-H,.F-[F-<L. &he :e)port cl#u!e !peci'ie! n#*e! th#t 6ill be e.tern#l in $;%.J9JI%;8M-H,.F-[F-<L #nd thu! #cce!!ible in p#c9#ge! th#t :'se it. &here'ore, #'ter you@?e de'ined thi! p#c9#ge, you c#n ch#nge the de'inition o' the *#in #pplic#tion p#c9#ge to the 'ollo6ing:
1de(pac&age#:com.gigamon&e?s.email-db ##1:'se#:common-lisp#:com.gigamon&e?s.te)t-db33
:o6 code 6ritten in $;%.J9JI%;8M-H,.-%I9L-<L c#n u!e unFu#li'ied n#*e! to re'er to the e.ported !y*bol! 'ro* both $;%%;8-L9,T #nd $;%.J9JI%;8M-H,.F-[F-<L. %ll other n#*e! 6ill continue to be interned directly in the $;%.J9JI%;8M-H,.-%I9L-<L p#c9#ge.
:o6 #ny6here the n#*e parse-email-address #ppe#r! in code re#d in the $;%.J9JI%;8M-H,.-%I9L-<L p#c9#ge, it 6ill be re#d #! the !y*bol 'ro* $;%.I$%-.-%I9L. I' you need to i*port *ore th#n one !y*bol 'ro* # !ingle p#c9#ge, you c#n include *ultiple n#*e! #'ter the p#c9#ge n#*e in # !ingle :import-(rom cl#u!e. % DEFPAC+AGE c#n #l!o include *ultiple :import-(rom cl#u!e! in order to i*port !y*bol! 'ro* di''erent p#c9#ge!. 5cc#!ion#lly you@ll run into the oppo!ite !itu#tion--# p#c9#ge *#y e.port # bunch o' n#*e! you 6#nt to u!e #nd # 'e6 you don@t. $#ther th#n li!ting #ll the !y*bol! you do 6#nt to u!e in #n :import(rom cl#u!e, you c#n in!te#d :'se the p#c9#ge #nd then li!t the n#*e! you don(t 6#nt to inherit in # :shadow cl#u!e. /or in!t#nce, !uppo!e the $;%.I$%-.F-[F p#c9#ge e.port! # bunch o' n#*e! o' 'unction! #nd cl#!!e! u!ed in te.t proce!!ing. /urther !uppo!e th#t *o!t o' the!e 'unction! #nd cl#!!e! #re one! you@ll 6#nt to u!e in your code, but one o' the n#*e!, b'ild-inde), con'lict! 6ith # n#*e you@?e #lre#dy u!ed. 4ou c#n *#9e the b'ild-inde) 'ro* $;%.I$%-.F-[F in#cce!!ible by !h#do6ing it.
1de(pac&age#:com.gigamon&e?s.email-db ##1:'se ###:common-lisp ###:com.gigamon&e?s.te)t-db ###:com.acme.te)t3 ##1:import-(rom#:com.acme.email#:parse-email-address3 ##1:shadow#:b'ild-inde)33
&he :shadow cl#u!e c#u!e! # ne6 !y*bol n#*ed L+9L<-98<-[ to be cre#ted #nd #dded directly to $;%.J9JI%;8M-H,.-%I9L-<L@! n#*e-to-!y*bol *#p. :o6 i' the re#der re#d! the n#*e L+9L<98<-[, it 6ill tr#n!l#te it to the !y*bol in $;%.J9JI%;8M-H,.-%I9L-<L@! *#p, r#ther th#n the one th#t 6ould other6i!e be inherited 'ro* $;%.I$%-.F-[F. &he ne6 !y*bol i! #l!o #dded to # shadowing s0mbols list th#t@! p#rt o' the $;%.J9JI%;8M-H,.-%I9L-<L p#c9#ge, !o i' you l#ter u!e #nother p#c9#ge th#t #l!o e.port! # L+9L<-98<-[ !y*bol, the p#c9#ge !y!te* 6ill 9no6 there@! no con'lict--th#t you 6#nt the !y*bol 'ro* $;%.J9JI%;8M-H,.-%I9L-<L to be u!ed r#ther th#n #ny other !y*bol! 6ith the !#*e n#*e inherited 'ro* other p#c9#ge!. % !i*il#r !itu#tion c#n #ri!e i' you 6#nt to u!e t6o p#c9#ge! th#t e.port the !#*e n#*e. In thi! c#!e the re#der 6on@t 9no6 6hich inherited n#*e to u!e 6hen it re#d! the te.tu#l n#*e. In !uch !itu#tion! you *u!t re!ol?e the #*biguity by !h#do6ing the con'licting n#*e!. I' you don@t need to u!e the n#*e 'ro* either p#c9#ge, you could !h#do6 the n#*e 6ith # :shadow cl#u!e, cre#ting # ne6 !y*bol 6ith the !#*e n#*e in your p#c9#ge. 7ut i' you #ctu#lly 6#nt to u!e one o' the inherited !y*bol!, then you need to re!ol?e the #*biguity 6ith # :shadowing-import-(rom cl#u!e. i9e #n :import(rom cl#u!e, # :shadowing-import-(rom cl#u!e con!i!t! o' # p#c9#ge n#*e 'ollo6ed by the n#*e! to i*port 'ro* th#t p#c9#ge. /or in!t#nce, i' $;%.I$%-.F-[F e.port! # n#*e ,IK- th#t con'lict! 6ith the n#*e e.ported 'ro* $;%.J9JI%;8M-H,.F-[F-<L, you could re!ol?e the #*biguity 6ith the 'ollo6ing DEFPAC+AGE:
1de(pac&age#:com.gigamon&e?s.email-db ##1:'se ###:common-lisp ###:com.gigamon&e?s.te)t-db ###:com.acme.te)t3 ##1:import-(rom#:com.acme.email#:parse-email-address3
##1:shadow#:b'ild-inde)3 ##1:shadowing-import-(rom#:com.gigamon&e?s.te)t-db#:save33
"ackaging +echanics
&h#t co?er! the b#!ic! o' ho6 to u!e p#c9#ge! to *#n#ge n#*e!p#ce! in !e?er#l co**on !itu#tion!. >o6e?er, #nother le?el o' ho6 to u!e p#c9#ge! i! 6orth di!cu!!ing--the r#6 *ech#nic! o' ho6 to org#niAe code th#t u!e! di''erent p#c9#ge!. In thi! !ection I@ll di!cu!! # 'e6 rule! o' thu*b #bout ho6 to org#niAe code--6here to put your DEFPAC+AGE 'or*! rel#ti?e to the code th#t u!e! your p#c9#ge! ?i# IN-PAC+AGE. 7ec#u!e p#c9#ge! #re u!ed by the re#der, # p#c9#ge *u!t be de'ined be'ore you c#n LOAD or COMPILE-FILE # 'ile th#t cont#in! #n IN-PAC+AGE e.pre!!ion !6itching to th#t p#c9#ge. P#c9#ge! #l!o *u!t be de'ined be'ore other DEFPAC+AGE 'or*! c#n re'er to the*. /or in!t#nce, i' you@re going to :'se $;%.J9JI%;8M-H,.F-[F-<L in $;%.J9JI%;8M-H,.-%I9L-<L, then $;%.J9JI%;8M-H,.F-[F-<L@! DEFPAC+AGE *u!t be e?#lu#ted be'ore the DEFPAC+AGE o' $;%.J9JI%;8M-H,.-%I9L-<L. &he be!t 'ir!t !tep to6#rd *#9ing !ure p#c9#ge! e.i!t 6hen they need to i! to put #ll your DEFPAC+AGE! in 'ile! !ep#r#te 'ro* the code th#t need! to be re#d in tho!e p#c9#ge!. So*e 'ol9! li9e to cre#te # (oo-pac&age.lisp 'ile 'or e#ch indi?idu#l p#c9#ge, #nd other! cre#te # !ingle pac&ages.lisp th#t cont#in! #ll the DEFPAC+AGE 'or*! 'or # group o' rel#ted p#c9#ge!. (ither #ppro#ch i! re#!on#ble, though the one-'ile-per-p#c9#ge #ppro#ch #l!o reFuire! th#t you #rr#nge to lo#d the indi?idu#l 'ile! in the right order #ccording to the interp#c9#ge dependencie!. (ither 6#y, once #ll the DEFPAC+AGE 'or*! h#?e been !ep#r#ted 'ro* the code th#t 6ill be re#d in the p#c9#ge! they de'ine, you c#n #rr#nge to LOAD the 'ile! cont#ining the DEFPAC+AGE! be'ore you co*pile or lo#d #ny o' the other 'ile!. /or !i*ple progr#*! you c#n do thi! by h#nd: !i*ply LOAD the 'ile or 'ile! cont#ining the DEFPAC+AGE 'or*!, po!!ibly co*piling the* 6ith COMPILE-FILE 'ir!t. &hen LOAD the 'ile! th#t u!e tho!e p#c9#ge!, #g#in option#lly co*piling the* 'ir!t 6ith COMPILEFILE. :ote, ho6e?er, th#t the p#c9#ge! don@t e.i!t until you LOAD the p#c9#ge de'inition!, either the !ource or the 'ile! produced by COMPILE-FILE. &hu!, i' you@re co*piling e?erything, you *u!t !till LOAD #ll the p#c9#ge de'inition! be'ore you c#n COMPILE-FILE #ny 'ile! to be re#d in the p#c9#ge!. +oing the!e !tep! by h#nd 6ill get tediou! #'ter # 6hile. /or !i*ple progr#*! you c#n #uto*#te the !tep! by 6riting # 'ile, load.lisp, th#t cont#in! the #ppropri#te LOAD #nd COMPILE-FILE c#ll! in the right order. &hen you c#n <u!t LOAD th#t 'ile. /or *ore co*ple. progr#*! you@ll 6#nt to u!e # s0stem definition '#cility to *#n#ge lo#ding #nd co*piling 'ile! in the right order.12 &he other 9ey rule o' thu*b i! th#t e#ch 'ile !hould cont#in e.#ctly one IN-PAC+AGE 'or*, #nd it !hould be the 'ir!t 'or* in the 'ile other th#n co**ent!. /ile! cont#ining DEFPAC+AGE 'or*! !hould !t#rt 6ith 1in-pac&age#4$;%%;8-L9,T-+,-.43, #nd #ll other 'ile! !hould cont#in #n INPAC+AGE o' one o' your p#c9#ge!. I' you ?iol#te thi! rule #nd !6itch p#c9#ge! in the *iddle o' # 'ile, you@ll con'u!e hu*#n re#der! 6ho don@t notice the !econd IN-PAC+AGE. %l!o, *#ny i!p de?elop*ent en?iron*ent!, p#rticul#rly (*#c!-b#!ed one! !uch #! S I3(, loo9 'or #n IN-PAC+AGE to deter*ine the p#c9#ge they !hould u!e 6hen co**unic#ting 6ith Co**on i!p. 3ultiple IN-PAC+AGE 'or*! per 'ile *#y con'u!e the!e tool! #! 6ell.
5n the other h#nd, it@! 'ine to h#?e *ultiple 'ile! re#d in the !#*e p#c9#ge, e#ch 6ith #n identic#l INPAC+AGE 'or*. It@! <u!t # *#tter o' ho6 you li9e to org#niAe your code. &he other bit o' p#c9#ging *ech#nic! h#! to do 6ith ho6 to n#*e p#c9#ge!. P#c9#ge n#*e! li?e in # 'l#t n#*e!p#ce--p#c9#ge n#*e! #re <u!t !tring!, #nd di''erent p#c9#ge! *u!t h#?e te.tu#lly di!tinct n#*e!. &hu!, you h#?e to con!ider the po!!ibility o' con'lict! bet6een p#c9#ge n#*e!. I' you@re u!ing only p#c9#ge! you de?eloped your!el', then you c#n prob#bly get #6#y 6ith u!ing !hort n#*e! 'or your p#c9#ge!. 7ut i' you@re pl#nning to u!e third-p#rty libr#rie! or to publi!h your code 'or u!e by other progr#**er!, then you need to 'ollo6 # n#*ing con?ention th#t 6ill *ini*iAe the po!!ibility o' n#*e colli!ion! bet6een di''erent p#c9#ge!. 3#ny i!per! the!e d#y! #re #dopting D#?#-!tyle n#*e!, li9e the one! u!ed in thi! ch#pter, con!i!ting o' # re?er!ed Internet do*#in n#*e 'ollo6ed by # dot #nd # de!cripti?e !tring.
"ackage &otchas
5nce you@re '#*ili#r 6ith p#c9#ge!, you 6on@t !pend # bunch o' ti*e thin9ing #bout the*. &here@! <u!t not th#t *uch to the*. >o6e?er, # couple o' gotch#! th#t bite *o!t ne6 i!p progr#**er! *#9e the p#c9#ge !y!te* !ee* *ore co*plic#ted #nd un'riendly th#n it re#lly i!. &he nu*ber-one gotch# #ri!e! *o!t co**only 6hen pl#ying #round #t the $(P . 4ou@ll be loo9ing #t !o*e libr#ry th#t de'ine! cert#in intere!ting 'unction!. 4ou@ll try to c#ll one o' the 'unction! li9e thi!:
$L-+,-./#1(oo3
%h, o' cour!e--you 'orgot to u!e the libr#ry@! p#c9#ge. So you Fuit the debugger #nd try to USEPAC+AGE the libr#ry@! p#c9#ge in order to get #cce!! to the n#*e E;; !o you c#n c#ll the 'unction.
$L-+,-./#1'se-pac&age#:(oolib3
7ut th#t drop! you b#c9 into the debugger 6ith thi! error *e!!#ge:
+sing#pac&age#BE;;L9LC#res'lts#in#name#con(licts#(or#these#s?mbols:#E;; ###D$ondition#o(#t?pe#TI$MIJ---..;.G .estarts: ## :#D$;8F98+-G#+nintern#the#con(licting#s?mbols#(rom#the#B$;%%;8-L9,T-+,-.C# pac&age. ##0:#DIL;.FG#Ibort#handling#,L9%-#re@'est. ##!:#DIL;.FG#Ibort#entirel?#(rom#this#1lisp3#process.
>uh" &he proble* i! the 'ir!t ti*e you c#lled (oo, the re#der re#d the n#*e (oo #nd interned it in $L-+,-. be'ore the e?#lu#tor got hold o' it #nd di!co?ered th#t thi! ne6ly interned !y*bol i!n@t the
n#*e o' # 'unction. &hi! ne6 !y*bol then con'lict! 6ith the !y*bol o' the !#*e n#*e e.ported 'ro* the E;;L9L p#c9#ge. I' you h#d re*e*bered to USE-PAC+AGE E;;L9L be'ore you tried to c#ll (oo, the re#der 6ould h#?e re#d (oo #! the inherited !y*bol #nd not interned # (oo !y*bol in $L+,-.. >o6e?er, #ll i!n@t lo!t, bec#u!e the 'ir!t re!t#rt o''ered by the debugger 6ill p#tch thing! up in <u!t the right 6#y: it 6ill unintern the (oo !y*bol 'ro* $;%%;8-L9,T-+,-., putting the $L-+,-. p#c9#ge b#c9 to the !t#te it 6#! in be'ore you c#lled (oo, #llo6ing the USE-PAC+AGE to proceed #nd #llo6ing 'or the inherited (oo to be #?#il#ble in $L-+,-.. &hi! 9ind o' proble* c#n #l!o occur 6hen lo#ding #nd co*piling 'ile!. /or in!t#nce, i' you de'ined # p#c9#ge, %H-ITT, 'or code th#t 6#! going to u!e 'unction! 6ith n#*e! 'ro* the E;;L9L p#c9#ge, but 'orgot to :'se E;;L9L, 6hen you co*pile the 'ile! 6ith #n 1in-pac&age#:m?-app3 in the*, the re#der 6ill intern ne6 !y*bol! in %H-ITT 'or the n#*e! th#t 6ere !uppo!ed to be re#d #! !y*bol! 'ro* E;;L9L. When you try to run the co*piled code, you@ll get unde'ined 'unction error!. I' you then try to rede'ine the %H-ITT p#c9#ge to :'se E;;L9L, you@ll get the con'licting !y*bol! error. &he !olution i! the !#*e: !elect the re!t#rt to unintern the con'licting !y*bol! 'ro* %H-ITT. 4ou@ll then need to reco*pile the code in the %H-ITT p#c9#ge !o it 6ill re'er to the inherited n#*e!. &he ne.t gotch# i! e!!enti#lly the re?er!e o' the 'ir!t gotch#. In thi! c#!e, you@d h#?e de'ined # p#c9#ge--#g#in, let@! !#y it@! %H-ITT--th#t u!e! #nother p#c9#ge, !#y, E;;L9L. :o6 you !t#rt 6riting code in the %H-ITT p#c9#ge. %lthough you u!ed E;;L9L in order to be #ble to re'er to the (oo 'unction, E;;L9L *#y e.port other !y*bol! #! 6ell. I' you u!e one o' tho!e e.ported !y*bol!--!#y, bar--#! the n#*e o' # 'unction in your o6n code, i!p 6on@t co*pl#in. In!te#d, the n#*e o' your 'unction 6ill be the !y*bol e.ported by E;;L9L, 6hich 6ill clobber the de'inition o' bar 'ro* E;;L9L. &hi! gotch# i! *ore in!idiou! bec#u!e it doe!n@t c#u!e #n error--'ro* the e?#lu#tor@! point o' ?ie6 it@! <u!t being #!9ed to #!!oci#te # ne6 'unction 6ith #n old n#*e, !o*ething th#t@! per'ectly leg#l. It@! !u!pect only bec#u!e the code doing the rede'ining 6#! re#d 6ith # di''erent ?#lue 'or *PAC+AGE* th#n the n#*e@! p#c9#ge. 7ut the e?#lu#tor doe!n@t nece!!#rily 9no6 th#t. >o6e?er, in *o!t i!p! you@ll get #n 6#rning #bout Hrede(ining#LI.5#originall?#de(ined#in"H. 4ou !hould heed tho!e 6#rning!. I' you clobber # de'inition 'ro* # libr#ry, you c#n re!tore it by relo#ding the libr#ry code 6ith LOAD.13 &he l#!t p#c9#ge-rel#ted gotch# i!, by co*p#ri!on, Fuite tri?i#l, but it bite! *o!t i!p progr#**er! #t le#!t # 'e6 ti*e!: you de'ine # p#c9#ge th#t u!e! $;%%;8-L9,T #nd *#ybe # 'e6 libr#rie!. &hen #t the $(P you ch#nge to th#t p#c9#ge to pl#y #round. &hen you decide to Fuit i!p #ltogether #nd try to c#ll 1@'it3. >o6e?er, @'it i!n@t # n#*e 'ro* the $;%%;8-L9,T p#c9#ge--it@! de'ined by the i*ple*ent#tion in !o*e i*ple*ent#tion-!peci'ic p#c9#ge th#t h#ppen! to be u!ed by $;%%;8-L9,T+,-.. &he !olution i! !i*ple--ch#nge p#c9#ge! b#c9 to $L-+,-. to Fuit. 5r u!e the S I3( $(P !hortcut @'it, 6hich 6ill #l!o !#?e you 'ro* h#?ing to re*e*ber th#t in cert#in Co**on i!p i*ple*ent#tion! the 'unction to Fuit i! e)it, not @'it. 4ou@re #l*o!t done 6ith your tour o' Co**on i!p. In the ne.t ch#pter I@ll di!cu!! the det#il! o' the e.tended LOOP *#cro. %'ter th#t, the re!t o' the boo9 i! de?oted to Hpr#ctic#l!H: # !p#* 'ilter, # libr#ry 'or p#r!ing bin#ry 'ile!, #nd ?#riou! p#rt! o' # !tre#*ing 3P3 !er?er 6ith # Web inter'#ce.
1&he
9ind o' progr#**ing th#t relie! on # !y*bol d#t# type i! c#lled, #ppropri#tely enough, s0mbolic co*put#tion. It@! typic#lly contr#!ted to numeric progr#**ing. %n e.#*ple o' # pri*#rily !y*bolic
progr#* th#t #ll progr#**er! !hould be '#*ili#r 6ith i! # co*piler--it tre#t! the te.t o' # progr#* #! !y*bolic d#t# #nd tr#n!l#te! it into # ne6 'or*.
2(?ery
p#c9#ge h#! one o''ici#l n#*e #nd Aero or *ore nic$names th#t c#n be u!ed #ny6here you need to u!e the p#c9#ge n#*e, !uch #! in p#c9#ge-Fu#li'ied n#*e! or to re'er to the p#c9#ge in # DEFPAC+AGE or IN-PAC+AGE 'or*.
3$;%%;8-L9,T-+,-.
i! #l!o #llo6ed to pro?ide #cce!! to !y*bol! e.ported by other i*ple*ent#tion-de'ined p#c9#ge!. While thi! i! intended #! # con?enience 'or the u!er--it *#9e! i*ple*ent#tion-!peci'ic 'unction#lity re#dily #cce!!ible--it c#n #l!o c#u!e con'u!ion 'or ne6 i!per!: i!p 6ill co*pl#in #bout #n #tte*pt to rede'ine !o*e n#*e th#t i!n@t li!ted in the l#ngu#ge !t#nd#rd. &o !ee 6h#t p#c9#ge! $;%%;8-L9,T-+,-. inherit! !y*bol! 'ro* in # p#rticul#r i*ple*ent#tion, e?#lu#te thi! e.pre!!ion #t the $(P :
1mapcar#NCpac&age-name#1pac&age-'se-list#:cl-'ser33
%nd to 'ind out 6h#t p#c9#ge # !y*bol c#*e 'ro* origin#lly, e?#lu#te thi!:
1pac&age-name#1s?mbol-pac&age#Csome-s?mbol33
Sy*bol! inherited 'ro* i*ple*ent#tion-de'ined p#c9#ge! 6ill return !o*e other ?#lue.
-&hi!
i! di''erent 'ro* the D#?# p#c9#ge !y!te*, 6hich pro?ide! # n#*e!p#ce 'or cl#!!e! but i! #l!o in?ol?ed in D#?#@! #cce!! control *ech#ni!*. &he non- i!p l#ngu#ge 6ith # p#c9#ge !y!te* *o!t li9e Co**on i!p@! p#c9#ge! i! Perl.
5%ll
the *#nipul#tion! per'or*ed by DEFPAC+AGE c#n #l!o be per'or*ed 6ith 'unction! th#t *#nipul#te p#c9#ge ob<ect!. >o6e?er, !ince # p#c9#ge gener#lly need! to be 'ully de'ined be'ore it c#n be u!ed, tho!e 'unction! #re r#rely u!ed. %l!o, DEFPAC+AGE t#9e! c#re o' per'or*ing #ll the p#c9#ge *#nipul#tion! in the right order--'or in!t#nce, DEFPAC+AGE #dd! !y*bol! to the !h#do6ing li!t be'ore it trie! to u!e the u!ed p#c9#ge!.
0In
*#ny i!p i*ple*ent#tion! the :'se cl#u!e i! option#l i' you 6#nt only to :'se $;%%;8L9,T--i' it@! o*itted, the p#c9#ge 6ill #uto*#tic#lly inherit n#*e! 'ro* #n i*ple*ent#tion-de'ined li!t o' p#c9#ge! th#t 6ill u!u#lly include $;%%;8-L9,T. >o6e?er, your code 6ill be *ore port#ble i' you #l6#y! e.plicitly !peci'y the p#c9#ge! you 6#nt to :'se. &ho!e 6ho #re #?er!e to typing c#n u!e the p#c9#ge@! nic9n#*e #nd 6rite 1:'se#:cl3.
28!ing
9ey6ord! in!te#d o' !tring! h#! #nother #d?#nt#ge--%llegro pro?ide! # H*odern *odeH i!p in 6hich the re#der doe! no c#!e con?er!ion o' n#*e! #nd in 6hich, in!te#d o' # COMMON-LISP p#c9#ge 6ith upperc#!e n#*e!, pro?ide! # common-lisp p#c9#ge 6ith lo6erc#!e n#*e!. Strictly !pe#9ing, thi! i!p i!n@t # con'or*ing Co**on i!p !ince #ll the n#*e! in the !t#nd#rd #re de'ined to be upperc#!e. 7ut i' you 6rite your DEFPAC+AGE 'or*! u!ing 9ey6ord !y*bol!, they 6ill 6or9 both in Co**on i!p #nd in thi! ne#r rel#ti?e.
,So*e
'ol9!, in!te#d o' 9ey6ord!, u!e uninterned !y*bol!, u!ing the N: !ynt#..
1de(pac&age#N:com.gigamon&e?s.email-db ##1:'se#N:common-lisp33
&hi! !#?e! # tiny bit o' *e*ory by not interning #ny !y*bol! in the 9ey6ord p#c9#ge--the !y*bol c#n beco*e g#rb#ge #'ter DEFPAC+AGE Bor the code it e.p#nd! intoC i! done 6ith it. >o6e?er, the di''erence i! !o !light th#t it re#lly boil! do6n to # *#tter o' #e!thetic!.
)&he
re#!on to u!e IN-PAC+AGE in!te#d o' <u!t SETFing *PAC+AGE* i! th#t IN-PAC+AGE e.p#nd! into code th#t 6ill run 6hen the 'ile i! co*piled by COMPILE-FILE #! 6ell #! 6hen the 'ile i! lo#ded, ch#nging the 6#y the re#der re#d! the re!t o' the 'ile during co*pil#tion.
10In
the $(P bu''er in S I3( you c#n #l!o ch#nge p#c9#ge! 6ith # $(P !hortcut. &ype # co**#, #nd then enter change-pac&age #t the $ommand: pro*pt.
11+uring
de?elop*ent, i' you try to :'se # p#c9#ge th#t e.port! # !y*bol 6ith the !#*e n#*e #! # !y*bol #lre#dy interned in the u!ing p#c9#ge, i!p 6ill !ign#l #n error #nd typic#lly o''er you # re!t#rt th#t 6ill unintern the o''ending !y*bol 'ro* the u!ing p#c9#ge. /or *ore on thi!, !ee the !ection HP#c9#ge =otch#!.H
12&he
code 'or the HPr#ctic#lH ch#pter!, #?#il#ble 'ro* thi! boo9@! Web !ite, u!e! the %S+/ !y!te* de'inition libr#ry. %S+/ !t#nd! 'or %nother Sy!te* +e'inition /#cility.
13So*e
Co**on i!p i*ple*ent#tion!, !uch #! %llegro #nd S7C , pro?ide # '#cility 'or Hloc9ingH the !y*bol! in # p#rticul#r p#c9#ge !o they c#n be u!ed in de'ining 'or*! !uch #! DEFUN, DEFVAR, #nd DEFCLASS only 6hen their ho*e p#c9#ge i! the current p#c9#ge.
&he LOOP *#cro h#! # lot o' p#rt!--one o' the *#in co*pl#int! o' LOOP@! detr#ctor! i! th#t it@! too co*ple.. In thi! ch#pter, I@ll t#c9le LOOP he#d on, gi?ing you # !y!te*#tic tour o' the ?#riou! p#rt! #nd ho6 they 'it together.
%ddition#lly, LOOP pro?ide! !ynt#. 'or the 'ollo6ing: Cre#ting loc#l ?#ri#ble! 'or u!e 6ithin the loop Speci'ying #rbitr#ry i!p e.pre!!ion! to run be'ore #nd #'ter the loop proper &he b#!ic !tructure o' # LOOP i! # !et o' cl#u!e!, e#ch o' 6hich begin! 6ith # loop $e0word.1 >o6 e#ch cl#u!e i! p#r!ed by the LOOP *#cro depend! on the 9ey6ord. So*e o' the *#in 9ey6ord!, 6hich you !#6 in Ch#pter 2, #re (or, collecting, s'mming, co'nting, do, #nd (inall?.
Iteration #ontro%
3o!t o' the !o-c#lled iter#tion control cl#u!e! !t#rt 6ith the loop 9ey6ord (or, or it! !ynony* as,2 'ollo6ed by the n#*e o' # ?#ri#ble. Wh#t 'ollo6! #'ter the ?#ri#ble n#*e depend! on the type o' (or cl#u!e. &he !ubcl#u!e! o' # (or cl#u!e c#n iter#te o?er the 'ollo6ing: $#nge! o' nu*ber!, up or do6n, by !peci'ied inter?#l! &he indi?idu#l ite*! o' # li!t &he con! cell! th#t *#9e up # li!t &he ele*ent! o' # ?ector, including !ubtype! !uch #! !tring! #nd bit ?ector! &he p#ir! o' # h#!h t#ble &he !y*bol! in # p#c9#ge &he re!ult! o' repe#tedly e?#lu#ting # gi?en 'or*
% !ingle loop c#n h#?e *ultiple (or cl#u!e! 6ith e#ch cl#u!e n#*ing it! o6n ?#ri#ble. When # loop h#! *ultiple (or cl#u!e!, the loop ter*in#te! #! !oon #! #ny (or cl#u!e re#che! it! end condition. /or in!t#nce, the 'ollo6ing loop:
1loop ##(or#item#in#list ##(or#i#(rom#0#to#0 ##do#1something33
6ill iter#te #t *o!t ten ti*e! but *#y !top !ooner i' list cont#in! 'e6er th#n ten ite*!.
#ounting Loops
%rith*etic iter#tion cl#u!e! control the nu*ber o' ti*e! the loop body 6ill be e.ecuted by !tepping # ?#ri#ble o?er # r#nge o' nu*ber!, e.ecuting the body once per !tep. &he!e cl#u!e! con!i!t o' 'ro* one to three o' the 'ollo6ing prepositional phrases #'ter the (or Bor asC: the from where phr#!e, the to where phr#!e, #nd the b0 how much phr#!e. &he from where phr#!e !peci'ie! the initi#l ?#lue o' the cl#u!e@! ?#ri#ble. It con!i!t! o' one o' the prepo!ition! (rom, down(rom, or 'p(rom 'ollo6ed by # 'or*, 6hich !upplie! the initi#l ?#lue B# nu*berC. &he to where phr#!e !peci'ie! # !topping point 'or the loop #nd con!i!t! o' one o' the prepo!ition! to, 'pto, below, downto, or above 'ollo6ed by # 'or*, 6hich !upplie! the !topping point. With 'pto #nd downto, the loop body 6ill be ter*in#ted B6ithout e.ecuting the body #g#inC 6hen the ?#ri#ble p#!!e! the !topping pointG 6ith below #nd above, it !top! one iter#tion e#rlier.&he b0 how much phr#!e con!i!t! o' the prepo!ition! b? #nd # 'or*, 6hich *u!t e?#lu#te to # po!iti?e nu*ber. &he ?#ri#ble 6ill be !tepped Bup or do6n, #! deter*ined by the other phr#!e!C by thi! #*ount on e#ch iter#tion or by one i' it@! o*itted. 4ou *u!t !peci'y #t le#!t one o' the!e prepo!ition#l phr#!e!. &he de'#ult! #re to !t#rt #t Aero, incre*ent the ?#ri#ble by one #t e#ch iter#tion, #nd go 'ore?er or, *ore li9ely, until !o*e other cl#u!e ter*in#te! the loop. 4ou c#n *odi'y #ny or #ll o' the!e de'#ult! by #dding the #ppropri#te prepo!ition#l phr#!e!. &he only 6rin9le i! th#t i' you 6#nt decre*ent#l !tepping, there@! no de'#ult from where ?#lue, !o you *u!t !peci'y one 6ith either (rom or down(rom. So, the 'ollo6ing:
1loop#(or#i#'pto#0 #collect#i3
collect! the 'ir!t ele?en integer! BAero to tenC, but the beh#?ior o' thi!:
1loop#(or#i#downto#-0 #collect#i3#########S#wrong
%l!o note th#t bec#u!e LOOP i! # *#cro, 6hich run! #t co*pile ti*e, it h#! to be #ble to deter*ine the direction to !tep the ?#ri#ble b#!ed !olely on the prepo!ition!--not the ?#lue! o' the 'or*!, 6hich *#y not be 9no6n until runti*e. So, the 'ollo6ing:
1loop#(or#i#(rom#0 #to#! #...3#
6on@t 9no6 to count do6n 'ro* t6enty to ten. Wor!e yet, it 6on@t gi?e you #n error--it 6ill <u!t not e.ecute the loop !ince i i! #lre#dy gre#ter th#n ten. In!te#d, you *u!t 6rite thi!:
1loop#(or#i#(rom#! #downto#0 #...3
or thi!:
1loop#(or#i#down(rom#! #to#0 #...3
/in#lly, i' you <u!t 6#nt # loop th#t repe#t! # cert#in nu*ber o' ti*e!, you c#n repl#ce # cl#u!e o' the 'ollo6ing 'or*:
(or#i#(rom#0#to#number-form
&he!e cl#u!e! #re identic#l in e''ect e.cept the repeat cl#u!e doe!n@t cre#te #n e.plicit loop ?#ri#ble.
!tep! var o?er #ll the ele*ent! o' the li!t produced by e?#lu#ting list)form.
1loop#(or#i#in#1list#0 #! #3 #4 3#collect#i3#==/#10 #! #3 #4 3
5cc#!ion#lly thi! cl#u!e i! !upple*ented 6ith # b? phr#!e, 6hich !peci'ie! # 'unction to u!e to *o?e do6n the li!t. &he de'#ult i! CDR but c#n be #ny 'unction th#t t#9e! # li!t #nd return! # !ubli!t. /or in!t#nce, you could collect e?ery other ele*ent o' # li!t 6ith # loop li9e thi!:
1loop#(or#i#in#1list#0 #! #3 #4 3#b?#NCcddr#collect#i3#==/#10 #3 3
%n on prepo!ition#l phr#!e i! u!ed to !tep var o?er the con! cell! th#t *#9e up # li!t.
1loop#(or#)#on#1list#0 #! #3 3#collect#)3#==/#110 #! #3 3#1! #3 3#13 33
ooping o?er the ele*ent! o' # ?ector B6hich include! !tring! #nd bit ?ector!C i! !i*il#r to looping o?er the ele*ent! o' # li!t e.cept the prepo!ition across i! u!ed in!te#d o' in.3 /or in!t#nce:
1loop#(or#)#across#4abcd4#collect#)3#==/#1NYa#NYb#NYc#NYd3
Iter#ting o?er # h#!h t#ble or p#c9#ge i! !lightly *ore co*plic#ted bec#u!e h#!h t#ble! #nd p#c9#ge! h#?e di''erent !et! o' ?#lue! you *ight 6#nt to iter#te o?er--the 9ey! or ?#lue! in # h#!h t#ble #nd the di''erent 9ind! o' !y*bol! in # p#c9#ge. 7oth 9ind! o' iter#tion 'ollo6 the !#*e p#ttern. &he b#!ic p#ttern loo9! li9e thi!:
1loop#(or#var#being#the#things#in#hash-or-package#...3
/or h#!h t#ble!, the po!!ible ?#lue! 'or things #re hash-&e?s #nd hash-val'es, 6hich c#u!e var# to be bound to !ucce!!i?e ?#lue! o' either the 9ey! or the ?#lue! o' the h#!h t#ble. &he hash)or)pac$age 'or* i! e?#lu#ted once to produce # ?#lue, 6hich *u!t be # h#!h t#ble. &o iter#te o?er # p#c9#ge, things c#n be s?mbols, present-s?mbols, #nd e)ternals?mbols, 6hich c#u!e var to be bound to e#ch o' the !y*bol! #cce!!ible in # p#c9#ge, e#ch o' the
!y*bol! pre!ent in # p#c9#ge Bin other 6ord!, interned or i*ported into th#t p#c9#geC, or e#ch o' the !y*bol! th#t h#?e been e.ported 'ro* the p#c9#ge. &he hash)or)pac$age 'or* i! e?#lu#ted to produce the n#*e o' # p#c9#ge, 6hich i! loo9ed up #! i' by FIND-PAC+AGE or # p#c9#ge ob<ect. Synony*! #re #l!o #?#il#ble 'or p#rt! o' the (or cl#u!e. In pl#ce o' the, you c#n u!e eachG you c#n u!e o( in!te#d o' inG #nd you c#n 6rite the things in the !ingul#r B'or e.#*ple, hash-&e? or s?mbolC. /in#lly, !ince you@ll o'ten 6#nt both the 9ey! #nd the ?#lue! 6hen iter#ting o?er # h#!h t#ble, the h#!h t#ble cl#u!e! !upport # 'sing !ubcl#u!e #t the end o' the h#!h t#ble cl#u!e.
1loop#(or#&#being#the#hash-&e?s#in#h#'sing#1hash-val'e#v3#...3 1loop#(or#v#being#the#hash-val'es#in#h#'sing#1hash-&e?#&3#...3
7oth o' the!e loop! 6ill bind & to e#ch 9ey in the h#!h t#ble #nd v to the corre!ponding ?#lue. :ote th#t the 'ir!t ele*ent o' the 'sing !ubcl#u!e *u!t be in the !ingul#r 'or*.-
!8ua%s4Then Iteration
I' none o' the other (or cl#u!e! !upport! e.#ctly the 'or* o' ?#ri#ble !tepping you need, you c#n t#9e co*plete control o?er !tepping 6ith #n e4uals)then cl#u!e. &hi! cl#u!e i! !i*il#r to the binding cl#u!e! in # DO loop but c#!t in # *ore %lgoli!h !ynt#.. &he te*pl#te i! #! 'ollo6!:
1loop#(or#var#=#initial-value-form#D#then#step-form#G#...3
%! u!u#l, var i! the n#*e o' the ?#ri#ble to be !tepped. It! initi#l ?#lue i! obt#ined by e?#lu#ting initial) value)form once be'ore the 'ir!t iter#tion. In e#ch !ub!eFuent iter#tion, step)form i! e?#lu#ted, #nd it! ?#lue beco*e! the ne6 ?#lue o' var. With no then p#rt to the cl#u!e, the initial)value)form i! ree?#lu#ted on e#ch iter#tion to pro?ide the ne6 ?#lue. :ote th#t thi! i! di''erent 'ro* # DO binding cl#u!e 6ith no !tep 'or*. &he step)form c#n re'er to other loop ?#ri#ble!, including ?#ri#ble! cre#ted by other (or cl#u!e! l#ter in the loop. /or in!t#nce:
1loop#repeat#"# ######(or#)#=# #then#? ######(or#?#=#0#then#12#)#?3 ######collect#?3#==/#10#!#4#R#063
>o6e?er, note th#t e#ch (or cl#u!e i! e?#lu#ted !ep#r#tely in the order it #ppe#r!. So in the pre?iou! loop, on the !econd iter#tion ) i! !et to the ?#lue o' ? be'ore ? ch#nge! Bin other 6ord!, 0C. 7ut ? i! then !et to the !u* o' it! old ?#lue B!till 0C #nd the ne6 ?#lue o' ). I' the order o' the (or cl#u!e! i! re?er!ed, the re!ult! ch#nge.
1loop#repeat#" ######(or#?#=#0#then#12#)#?3 ######(or#)#=# #then#? ######collect#?3#==/#10#0#!#4#R3
5'ten, ho6e?er, you@ll 6#nt the !tep 'or*! 'or *ultiple ?#ri#ble! to be e?#lu#ted be'ore #ny o' the ?#ri#ble! i! gi?en it! ne6 ?#lue B!i*il#r to ho6 DO !tep! it! ?#ri#ble!C. In th#t c#!e, you c#n <oin *ultiple (or cl#u!e! by repl#cing #ll but the 'ir!t (or 6ith and. 4ou !#6 thi! 'or*ul#tion #lre#dy in the LOOP ?er!ion o' the /ibon#cci co*put#tion in Ch#pter 2. >ere@! #nother ?#ri#nt, b#!ed on the t6o pre?iou! e.#*ple!:
1loop#repeat#"#
Loca% <aria2%es
While the *#in ?#ri#ble! needed 6ithin # loop #re u!u#lly decl#red i*plicitly in (or cl#u!e!, !o*eti*e! you@ll need #u.ili#ry ?#ri#ble!, 6hich you c#n decl#re 6ith with cl#u!e!.
with#var#D#=#value-form#G
&he n#*e var beco*e! the n#*e o' # loc#l ?#ri#ble th#t 6ill ce#!e to e.i!t 6hen the loop 'ini!he!. I' the with cl#u!e cont#in! #n = val'e-(orm p#rt, the ?#ri#ble 6ill be initi#liAed, be'ore the 'ir!t iter#tion o' the loop, to the ?#lue o' value)form. 3ultiple with cl#u!e! c#n #ppe#r in # loopG e#ch cl#u!e i! e?#lu#ted independently in the order it #ppe#r! #nd the ?#lue i! #!!igned be'ore proceeding to the ne.t cl#u!e, #llo6ing l#ter ?#ri#ble! to depend on the ?#lue o' #lre#dy decl#red ?#ri#ble!. 3utu#lly independent ?#ri#ble! c#n be decl#red in one with cl#u!e 6ith #n and bet6een e#ch decl#r#tion.
1estructuring <aria2%es
5ne h#ndy 'e#ture o' LOOP I h#?en@t *entioned yet i! the #bility to de!tructure li!t ?#lue! #!!igned to loop ?#ri#ble!. &hi! let! you t#9e #p#rt the ?#lue o' li!t! th#t 6ould other6i!e be #!!igned to # loop ?#ri#ble, !i*il#r to the 6#y DESTRUCTURING-BIND 6or9! but # bit le!! el#bor#te. 7#!ic#lly, you c#n repl#ce #ny loop ?#ri#ble in # (or or with cl#u!e 6ith # tree o' !y*bol!, #nd the li!t ?#lue th#t 6ould h#?e been #!!igned to the !i*ple ?#ri#ble 6ill in!te#d be de!tructured into ?#ri#ble! n#*ed by the !y*bol! in the tree. % !i*ple e.#*ple loo9! li9e thi!:
$L-+,-./#1loop#(or#1a#b3#in#C110#!3#13#43#1"#633 ############do#1(ormat#t#4a:#7aS#b:#7a764#a#b33 a:#0S#b:#! a:#3S#b:#4 a:#"S#b:#6 89L
&he tree c#n #l!o include dotted li!t!, in 6hich c#!e the n#*e #'ter the dot #ct! li9e # &&'(! p#r#*eter, being bound to # li!t cont#ining #ny re*#ining ele*ent! o' the li!t. &hi! i! p#rticul#rly h#ndy 6ith (or;on loop! !ince the ?#lue i! #l6#y! # li!t. /or in!t#nce, thi! LOOP B6hich I u!ed in Ch#pter 1, to e*it # co**#-deli*ited li!tC:
1loop#(or#cons#on#list ####do#1(ormat#t#47a4#1car#cons33 ####when#1cdr#cons3#do#1(ormat#t#45#433
I' you 6#nt to ignore # ?#lue in the de!tructured li!t, you c#n u!e NIL in pl#ce o' # ?#ri#ble n#*e.
1loop#(or#1a#nil3#in#C110#!3#13#43#1"#633#collect#a3#==/#10#3#"3
I' the de!tructuring li!t cont#in! *ore ?#ri#ble! th#n there #re ?#lue! in the li!t, the e.tr# ?#ri#ble! #re !et to NIL, *#9ing #ll the ?#ri#ble! e!!enti#lly li9e &o !"o#$% p#r#*eter!. &here i!n@t, ho6e?er, #ny eFui?#lent to &)'* p#r#*eter!.
<a%ue Accu$u%ation
&he ?#lue #ccu*ul#tion cl#u!e! #re perh#p! the *o!t po6er'ul p#rt o' LOOP. While the iter#tion control cl#u!e! pro?ide # conci!e !ynt#. 'or e.pre!!ing the b#!ic *ech#nic! o' looping, they #ren@t dr#*#tic#lly di''erent 'ro* the eFui?#lent *ech#ni!*! pro?ided by DO, DOLIST, #nd DOTIMES. &he ?#lue #ccu*ul#tion cl#u!e!, on the other h#nd, pro?ide # conci!e not#tion 'or # h#nd'ul o' co**on loop idio*! h#?ing to do 6ith #ccu*ul#ting ?#lue! 6hile looping. (#ch #ccu*ul#tion cl#u!e !t#rt! 6ith # ?erb #nd 'ollo6! thi! p#ttern:
verb#form#D#into#var#G
(#ch ti*e through the loop, #n #ccu*ul#tion cl#u!e e?#lu#te! form #nd !#?e! the ?#lue in # *#nner deter*ined by the verb. With #n into !ubcl#u!e, the ?#lue i! !#?ed into the ?#ri#ble n#*ed by var. &he ?#ri#ble i! loc#l to the loop, #! i' it@d been decl#red in # with cl#u!e. With no into !ubcl#u!e, the #ccu*ul#tion cl#u!e in!te#d #ccu*ul#te! # de'#ult ?#lue 'or the 6hole loop e.pre!!ion. &he po!!ible ?erb! #re collect, append, nconc, co'nt, s'm, ma)imi*e, #nd minimi*e. %l!o #?#il#ble #! !ynony*! #re the pre!ent p#rticiple 'or*!: collecting, appending, nconcing, co'nting, s'mming, ma)imi*ing, #nd minimi*ing. % collect cl#u!e build! up # li!t cont#ining #ll the ?#lue! o' form in the order they@re !een. &hi! i! # p#rticul#rly u!e'ul con!truct bec#u!e the code you@d h#?e to 6rite to collect # li!t in order #! e''iciently #! LOOP doe! i! *ore p#in'ul th#n you@d nor*#lly 6rite by h#nd.5 $el#ted to collect #re the ?erb! append #nd nconc. &he!e ?erb! #l!o #ccu*ul#te ?#lue! into # li!t, but they <oin the ?#lue!, 6hich *u!t be li!t!, into # !ingle li!t #! i' by the 'unction! APPEND or NCONC. 0 &he re*#ining #ccu*ul#tion cl#u!e! #re u!ed to #ccu*ul#te nu*eric ?#lue!. &he ?erb co'nt count! the nu*ber o' ti*e! form i! true, s'm collect! # running tot#l o' the ?#lue! o' form, ma)imi*e collect! the l#rge!t ?#lue !een 'or form, #nd minimi*e collect! the !*#lle!t. /or in!t#nce, !uppo!e you de'ine # ?#ri#ble UrandomU th#t cont#in! # li!t o' r#ndo* nu*ber!.
1de(parameter#UrandomU#1loop#repeat#0 #collect#1random#0 333
&hen the 'ollo6ing loop 6ill return # li!t cont#ining ?#riou! !u**#ry in'or*#tion #bout the nu*ber!:
1loop#(or#i#in#UrandomU ###co'nting#1evenp#i3#into#evens ###co'nting#1oddp#i3#into#odds ###s'mming#i#into#total ###ma)imi*ing#i#into#ma) ###minimi*ing#i#into#min ###(inall?#1ret'rn#1list#min#ma)#total#evens#odds333
'nconditiona% !)ecution
%! u!e'ul #! the ?#lue #ccu*ul#tion con!truct! #re, LOOP 6ouldn@t be # ?ery good gener#l-purpo!e
iter#tion '#cility i' there 6#!n@t # 6#y to e.ecute #rbitr#ry i!p code in the loop body. &he !i*ple!t 6#y to e.ecute #rbitr#ry code 6ithin # loop body i! 6ith # do cl#u!e. Co*p#red to the cl#u!e! I@?e de!cribed !o '#r, 6ith their prepo!ition! #nd !ubcl#u!e!, do i! # *odel o' 4od#e!Fue !i*plicity.2 % do cl#u!e con!i!t! o' the 6ord do Bor doingC 'ollo6ed by one or *ore i!p 'or*! th#t #re #ll e?#lu#ted 6hen the do cl#u!e i!. &he do cl#u!e end! #t the clo!ing p#renthe!i! o' the loop or the ne.t loop 9ey6ord. /or in!t#nce, to print the nu*ber! 'ro* one to ten, you could 6rite thi!:
1loop#(or#i#(rom#0#to#0 #do#1print#i33
%nother, *ore dr#*#tic, 'or* o' i**edi#te e.ecution i! # ret'rn cl#u!e. &hi! cl#u!e con!i!t! o' the 6ord ret'rn 'ollo6ed by # !ingle i!p 'or*, 6hich i! e?#lu#ted, 6ith the re!ulting ?#lue i**edi#tely returned #! the ?#lue o' the loop. 4ou c#n #l!o bre#9 out o' # loop in # do cl#u!e u!ing #ny o' i!p@! nor*#l control 'lo6 oper#tor!, !uch #! RETURN #nd RETURN-FROM. :ote th#t # ret'rn cl#u!e #l6#y! return! 'ro* the i**edi#tely enclo!ing LOOP e.pre!!ion, 6hile # RETURN or RETURN-FROM in # do cl#u!e c#n return 'ro* #ny enclo!ing e.pre!!ion. /or in!t#nce, co*p#re the 'ollo6ing:
1bloc&#o'ter ##1loop#(or#i#(rom# #ret'rn#0 ##1print#4Fhis#will#print43 ##! 3#==/#! 3#S#0 #ret'rned#(rom#L;;T
to thi!:
1bloc&#o'ter ##1loop#(or#i#(rom# #do#1ret'rn-(rom#o'ter#0 ##1print#4Fhis#wonCt#print43 ##! 3#==/#0 33#S#0 #ret'rned#(rom#LL;$M
&he do #nd ret'rn cl#u!e! #re collecti?ely c#lled the unconditional e3ecution cl#u!e!.
#onditiona% !)ecution
7ec#u!e # do cl#u!e c#n cont#in #rbitr#ry i!p 'or*!, you c#n u!e #ny i!p e.pre!!ion! you 6#nt, including control con!truct! !uch #! IF #nd WHEN. So, the 'ollo6ing i! one 6#y to 6rite # loop th#t print! only the e?en nu*ber! bet6een one #nd ten:
1loop#(or#i#(rom#0#to#0 #do#1when#1evenp#i3#1print#i333
>o6e?er, !o*eti*e! you@ll 6#nt condition#l control #t the le?el o' loop cl#u!e!. /or in!t#nce, !uppo!e you 6#nted to !u* only the e?en nu*ber! bet6een one #nd ten u!ing # s'mming cl#u!e. 4ou couldn@t 6rite !uch # loop 6ith # do cl#u!e bec#u!e there@d be no 6#y to Hc#llH the s'm#i in the *iddle o' # regul#r i!p 'or*. In c#!e! li9e thi!, you need to u!e one o' LOOP@! o6n condition#l e.pre!!ion! li9e thi!:
1loop#(or#i#(rom#0#to#0 #when#1evenp#i3#s'm#i3#==/#3
LOOP pro?ide! three condition#l con!truct!, #nd they #ll 'ollo6 thi! b#!ic p#ttern:
conditional#test-form#loop-clause
&he conditional c#n be i(, when, or 'nless. &he test)form i! #ny regul#r i!p 'or*, #nd loop)clause c#n be # ?#lue #ccu*ul#tion cl#u!e Bco'nt< collect< and so on@< an unconditional e3ecution cl#u!e, or #nother condition#l e.ecution cl#u!e. 3ultiple loop cl#u!e! c#n be #tt#ched to # !ingle condition#l by <oining the* 6ith and. %! #n e.tr# bit o' !ynt#ctic !ug#r, 6ithin the 'ir!t loop cl#u!e, #'ter the te!t 'or*, you c#n u!e the ?#ri#ble it to re'er to the ?#lue returned by the te!t 'or*. /or in!t#nce, the 'ollo6ing loop collect! the non-NIL ?#lue! 'ound in some-hash 6hen loo9ing up the 9ey! in some-list:
1loop#(or#&e?#in#some-list#when#1gethash#&e?#some-hash3#collect#it3
% condition#l cl#u!e i! e.ecuted e#ch ti*e through the loop. %n i( or when cl#u!e e.ecute! it! loop) clause i' test)form e?#lu#te! to true. %n 'nless re?er!e! the te!t, e.ecuting loop)clause only 6hen test)form i! NIL. 8nli9e their Co**on i!p n#*e!#9e!, LOOP@! i( #nd when #re *erely !ynony*!-there@! no di''erence in their beh#?ior. %ll three condition#l cl#u!e! c#n #l!o t#9e #n else br#nch, 6hich i! 'ollo6ed by #nother loop cl#u!e or *ultiple cl#u!e! <oined by and. When condition#l cl#u!e! #re ne!ted, the !et o' cl#u!e! connected to #n inner condition#l cl#u!e c#n be clo!ed 6ith the 6ord end. &he end i! option#l 6hen not needed to di!#*bigu#te # ne!ted condition#l--the end o' # condition#l cl#u!e 6ill be in'erred 'ro* the end o' the loop or the !t#rt o' #nother cl#u!e not <oined by and. &he 'ollo6ing r#ther !illy loop de*on!tr#te! the ?#riou! 'or*! o' LOOP condition#l!. &he 'pdateanal?sis 'unction 6ill be c#lled e#ch ti*e through the loop 6ith the l#te!t ?#lue! o' the ?#riou! ?#ri#ble! #ccu*ul#ted by the cl#u!e! 6ithin the condition#l!.
1loop#(or#i#(rom#0#to#0 ######i(#1evenp#i3 ########minimi*e#i#into#min-even#and# ########ma)imi*e#i#into#ma)-even#and ########'nless#1*erop#1mod#i#433 ##########s'm#i#into#even-not-(o'rs-total ########end ########and#s'm#i#into#even-total ######else ########minimi*e#i#into#min-odd#and ########ma)imi*e#i#into#ma)-odd#and ########when#1*erop#1mod#i#"33# ##########s'm#i#into#(ives-total ########end ########and#s'm#i#into#odd-total ######do#1'pdate-anal?sis#min-even ##########################ma)-even ##########################min-odd ##########################ma)-odd ##########################even-total ##########################odd-total ##########################(ives-total ##########################even-not-(o'rs-total33
th#t doe! !o*ething 6ith the ?#lue! co*puted by the loop. % tri?i#l e.#*ple, in Perl,, *ight loo9 li9e thi!:
m?#\evens=s'm#=# S m?#\odds=s'm##=# S (oreach#m?#\i#1Plist=o(=n'mbers3#V ##i(#1\i#6#!3#V ####\odds=s'm#2=#\iS ##W#else#V ####\evens=s'm#2=#\iS ##W W i(#1\evens=s'm#/#\odds=s'm3#V ##print#4,'m#o(#evens#greaterYn4S W#else#V ##print#4,'m#o(#odds#greaterYn4S W
&he loop proper in thi! code i! the (oreach !t#te*ent. 7ut the (oreach loop doe!n@t !t#nd on it! o6n: the code in the loop body re'er! to ?#ri#ble! decl#red in the t6o line! be'ore the loop.) %nd the 6or9 the loop doe! i! #ll 'or n#ught 6ithout the i( !t#te*ent #'ter the loop th#t #ctu#lly report! the re!ult!. In Co**on i!p, o' cour!e, the LOOP con!truct i! #n e.pre!!ion th#t return! # ?#lue, !o there@! e?en *ore o'ten # need to do !o*ething #'ter the loop proper, n#*ely, gener#te the return ?#lue. So, !#id the LOOP de!igner!, let@! gi?e # 6#y to include the code th#t@! re#lly p#rt o' the loop in the loop it!el'. &hu!, LOOP pro?ide! t6o 9ey6ord!, initiall? #nd (inall?, th#t introduce code to be run out!ide the loop@! *#in body. %'ter the initiall? or (inall?, the!e cl#u!e! con!i!t o' #ll the i!p 'or*! up to the !t#rt o' the ne.t loop cl#u!e or the end o' the loop. %ll the initiall? 'or*! #re co*bined into # !ingle prologue, 6hich run! once, i**edi#tely #'ter #ll the loc#l loop ?#ri#ble! #re initi#liAed #nd be'ore the body o' the loop. &he (inall? 'or*! #re !i*il#rly co*bined into # epilogue to be run #'ter the l#!t iter#tion o' the loop body. 7oth the prologue #nd epilogue code c#n re'er to loc#l loop ?#ri#ble!. &he prologue i! #l6#y! run, e?en i' the loop body iter#te! Aero ti*e!. &he loop c#n return 6ithout running the epilogue i' #ny o' the 'ollo6ing h#ppen!: % ret'rn cl#u!e e.ecute!. RETURN , RETURN-FROM, or #nother tr#n!'er o' control con!truct i! c#lled 'ro* 6ithin # i!p 'or* 6ithin the body.10 &he loop i! ter*in#ted by #n alwa?s, never, or thereis cl#u!e, #! I@ll di!cu!! in the ne.t !ection. Within the epilogue code, RETURN or RETURN-FROM c#n be u!ed to e.plicitly pro?ide # return ?#lue 'or the loop. Such #n e.plicit return ?#lue 6ill t#9e precedence o?er #ny ?#lue th#t *ight other6i!e be pro?ided by #n #ccu*ul#tion or ter*in#tion te!t cl#u!e. &o #llo6 RETURN-FROM to be u!ed to return 'ro* # !peci'ic loop Bu!e'ul 6hen ne!ting LOOP e.pre!!ion!C, you c#n n#*e # LOOP 6ith the loop 9ey6ord named. I' # named cl#u!e #ppe#r! in # loop, it *u!t be the 'ir!t cl#u!e. /or # !i*ple e.#*ple, #!!u*e lists i! # li!t o' li!t! #nd you 6#nt to 'ind #n ite* th#t *#tche! !o*e criteri# in one o' tho!e ne!ted li!t!. 4ou could 'ind it 6ith # p#ir o' ne!ted loop! li9e thi!:
1loop#named#o'ter#(or#list#in#lists#do #####1loop#(or#item#in#list#do
##########1i(#1what-i-am-loo&ing-(or-p#item3 ############1ret'rn-(rom#o'ter#item3333
Ter$ination Tests
While the (or #nd repeat cl#u!e! pro?ide the b#!ic in'r#!tructure 'or controlling the nu*ber o' iter#tion!, !o*eti*e! you@ll need to bre#9 out o' # loop e#rly. 4ou@?e #lre#dy !een ho6 # ret'rn cl#u!e or # RETURN or RETURN-FROM 6ithin # do cl#u!e c#n i**edi#tely ter*in#te the loopG but <u!t #! there #re co**on p#ttern! 'or #ccu*ul#ting ?#lue!, there #re #l!o co**on p#ttern! 'or deciding 6hen it@! ti*e to b#il on # loop. &he!e p#ttern! #re !upported in LOOP by the ter*in#tion cl#u!e!, while, 'ntil, alwa?s, never, #nd thereis. &hey #ll 'ollo6 the !#*e p#ttern.
loop-keyword#test-form
%ll 'i?e e?#lu#te test)form e#ch ti*e through the iter#tion #nd decide, b#!ed on the re!ulting ?#lue, 6hether to ter*in#te the loop. &hey di''er in 6h#t h#ppen! #'ter they ter*in#te the loop--i' they do-#nd ho6 they decide. &he loop 9ey6ord! while #nd 'ntil introduce the H*ildH ter*in#tion cl#u!e!. When they decide to ter*in#te the loop, control p#!!e! to the epilogue, !9ipping the re!t o' the loop body. &he epilogue c#n then return # ?#lue or do 6h#te?er it 6#nt! to 'ini!h the loop. % while cl#u!e ter*in#te! the loop the 'ir!t ti*e the te!t 'or* i! '#l!eG 'ntil, con?er!ely, !top! it the 'ir!t ti*e the te!t 'or* i! true. %nother 'or* o' *ild ter*in#tion i! pro?ided by the LOOP-FINISH *#cro. &hi! i! # regul#r i!p 'or*, not # loop cl#u!e, !o it c#n be u!ed #ny6here 6ithin the i!p 'or*! o' # do cl#u!e. It #l!o c#u!e! #n i**edi#te <u*p to the loop epilogue. It c#n be u!e'ul 6hen the deci!ion to bre#9 out o' the loop c#n@t be e#!ily conden!ed into # !ingle 'or* th#t c#n be u!ed 6ith # while or 'ntil cl#u!e. &he other three cl#u!e!--alwa?s, never, #nd thereis--ter*in#te the loop 6ith e.tre*e pre<udiceG they i**edi#tely return 'ro* the loop, !9ipping not only #ny !ub!eFuent loop cl#u!e! but #l!o the epilogue. &hey #l!o pro?ide # de'#ult ?#lue 'or the loop e?en 6hen they don@t c#u!e the loop to ter*in#te. >o6e?er, i' the loop i! not ter*in#ted by one o' the!e ter*in#tion te!t!, the epilogue i! run #nd c#n return # ?#lue other th#n the de'#ult pro?ided by the ter*in#tion cl#u!e!. 7ec#u!e the!e cl#u!e! pro?ide their o6n return ?#lue!, they c#n@t be co*bined 6ith #ccu*ul#tion cl#u!e! unle!! the #ccu*ul#tion cl#u!e h#! #n into !ubcl#u!e. &he co*piler Bor interpreterC !hould !ign#l #n error #t co*pile ti*e i' they #re.&he alwa?s #nd never cl#u!e! return only boole#n ?#lue!, !o they@re *o!t u!e'ul 6hen you need to u!e # loop e.pre!!ion #! p#rt o' # predic#te. 4ou c#n u!e alwa?s to chec9 th#t the te!t 'or* i! true on e?ery iter#tion o' the loop. Con?er!ely, never te!t! th#t the te!t 'or* e?#lu#te! to NIL on e?ery iter#tion. I' the te!t 'or* '#il! Breturning NIL in #n alwa?s cl#u!e or non-NIL in # never cl#u!eC, the loop i! i**edi#tely ter*in#ted, returning NIL. I' the loop run! to co*pletion, the de'#ult ?#lue o' T i! pro?ided. /or in!t#nce, i' you 6#nt to te!t th#t #ll the nu*ber! in # li!t, n'mbers, #re e?en, you c#n 6rite thi!:
1i(#1loop#(or#n#in#n'mbers#alwa?s#1evenp#n33 ####1print#4Ill#n'mbers#even.433
% thereis cl#u!e i! u!ed to te!t 6hether the te!t 'or* i! ever true. %! !oon #! the te!t 'or* return! # non-NIL ?#lue, the loop i! ter*in#ted, returning th#t ?#lue. I' the loop run! to co*pletion, the thereis cl#u!e pro?ide! # de'#ult return ?#lue o' NIL.
1loop#(or#char#across#4abc0!34#thereis#1digit-char-p#char33#==/#0 1loop#(or#char#across#4abcde(4#thereis#1digit-char-p#char33#==/#89L
ter* loop $e0word i! # bit un'ortun#te, #! loop 9ey6ord! #ren@t 9ey6ord! in the nor*#l !en!e o' being !y*bol! in the M-HW;.< p#c9#ge. In '#ct, #ny !y*bol, 'ro* #ny p#c9#ge, 6ith the #ppropri#te n#*e 6ill doG the LOOP *#cro c#re! only #bout their n#*e!. &ypic#lly, though, they@re 6ritten 6ith no p#c9#ge Fu#li'ier #nd #re thu! re#d B#nd interned #! nece!!#ryC in the current p#c9#ge.
27ec#u!e
one o' the go#l! o' LOOP i! to #llo6 loop e.pre!!ion! to be 6ritten 6ith # Fu#!i-(ngli!h !ynt#., *#ny o' the 9ey6ord! h#?e !ynony*! th#t #re tre#ted the !#*e by LOOP but #llo6 !o*e 'reedo* to e.pre!! thing! in !lightly *ore idio*#tic (ngli!h 'or di''erent conte.t!.
34ou
*#y 6onder 6hy LOOP c#n@t 'igure out 6hether it@! looping o?er # li!t or # ?ector 6ithout
needing di''erent prepo!ition!. &hi! i! #nother con!eFuence o' LOOP being # *#cro: the ?#lue o' the li!t or ?ector 6on@t be 9no6n until runti*e, but LOOP, #! # *#cro, h#! to gener#te code #t co*pile ti*e. %nd LOOP@! de!igner! 6#nted it to gener#te e.tre*ely e''icient code. &o be #ble to gener#te e''icient code 'or looping #cro!!, !#y, # ?ector, it need! to 9no6 #t co*pile ti*e th#t the ?#lue 6ill be # ?ector #t runti*e--thu!, the di''erent prepo!ition! #re needed.
-+on@t 5&he
#!9 *e 6hy LOOP@! #uthor! chic9ened out on the no-p#renthe!e! !tyle 'or the :("#; !ubcl#u!e.
tric9 i! to 9eep #hold o' the t#il o' the li!t #nd #dd ne6 con! cell! by SETFing the CDR o' the t#il. % h#nd6ritten eFui?#lent o' the code gener#ted by 1loop#(or#i#'pto#0 #collect#i3 6ould loo9 li9e thi!:
1do#11list#nil3#1tail#nil3#1i# #102#i333 ####11/#i#0 3#list3 ##1let#11new#1cons#i#nil333 ####1i(#1n'll#list3 ########1set(#list#new3 ########1set(#1cdr#tail3#new33 ####1set(#tail#new333
5' cour!e you@ll r#rely, i' e?er, 6rite code li9e th#t. 4ou@ll u!e either LOOP or Bi', 'or !o*e re#!on, you don@t 6#nt to u!e LOOPC the !t#nd#rd PUSH;NREVERSE idio* 'or collecting ?#lue!.
0$ec#ll
th#t NCONC i! the de!tructi?e ?er!ion o' APPEND--it@! !#'e to u!e #n nconc cl#u!e only i' the ?#lue! you@re collecting #re 're!h li!t! th#t don@t !h#re #ny !tructure 6ith other li!t!. /or in!t#nce, thi! i! !#'e:
1loop#(or#i#'pto#3#nconc#1list#i#i33#==/#1 # #0#0#!#!#3#33
&he l#ter 6ill *o!t li9ely get into #n in'inite loop #! the ?#riou! p#rt! o' the li!t produced by Bli!t 1 2 3C #re de!tructi?ely *odi'ied to point to e#ch other. 7ut e?en th#t@! not gu#r#nteed--the beh#?ior i! !i*ply unde'ined.
2H:oP &ry not. ,I@*
not pic9ing on Perl here--thi! e.#*ple 6ould loo9 pretty *uch the !#*e in #ny l#ngu#ge th#t b#!e! it! !ynt#. on C@!.
)Perl
6ould let you get #6#y 6ith not decl#ring tho!e ?#ri#ble! i' your progr#* didn@t 'se#strict. 7ut you !hould alwa0s 'se#strict in Perl. &he eFui?#lent code in Python, D#?#, or C 6ould #l6#y! reFuire the ?#ri#ble! to be decl#red.
104ou
c#n c#u!e # loop to 'ini!h nor*#lly, running the epilogue, 'ro* i!p code e.ecuted #! p#rt o' the loop body 6ith the loc#l *#cro LOOP-FINISH.
11So*e 12&he
Co**on i!p i*ple*ent#tion! 6ill let you get #6#y 6ith *i.ing body cl#u!e! #nd (or cl#u!e!, but th#t@! !trictly unde'ined, #nd !o*e i*ple*ent#tion! 6ill re<ect !uch loop!. one #!pect o' LOOP I h#?en@t touched on #t #ll i! the !ynt#. 'or decl#ring the type! o' loop ?#ri#ble!. 5' cour!e, I h#?en@t di!cu!!ed type decl#r#tion! out!ide o' LOOP either. I@ll co?er the gener#l topic # bit in Ch#pter 32. /or in'or*#tion on ho6 they 6or9 6ith LOOP, con!ult your '#?orite Co**on i!p re'erence.
&o #?oid h#?ing to thin9 li9e # !p#**er, =r#h#* decided to try di!tingui!hing !p#* 'ro* non!p#*, #.9.#. ham, b#!ed on !t#ti!tic! g#thered #bout 6hich 6ord! occur in 6hich 9ind! o' e-*#il!. &he 'ilter 6ould 9eep tr#c9 o' ho6 o'ten !peci'ic 6ord! #ppe#r in both !p#* #nd h#* *e!!#ge! #nd then u!e the 'reFuencie! #!!oci#ted 6ith the 6ord! in # ne6 *e!!#ge to co*pute # prob#bility th#t it 6#! either !p#* or h#*. >e c#lled hi! #ppro#ch #a0esian 'iltering #'ter the !t#ti!tic#l techniFue th#t he u!ed to co*bine the indi?idu#l 6ord 'reFuencie! into #n o?er#ll prob#bility.2
%ny 'ile cont#ining code 'or thi! #pplic#tion !hould !t#rt 6ith thi! line:
1in-pac&age#:com.gigamon&e?s.spam3
4ou c#n u!e the !#*e p#c9#ge n#*e or repl#ce com.gigamon&e?s 6ith !o*e do*#in you control.3 4ou c#n #l!o type thi! !#*e 'or* #t the $(P to !6itch to thi! p#c9#ge to te!t the 'unction! you 6rite. In S I3( thi! 6ill ch#nge the pro*pt 'ro* $L-+,-./ to ,TI%/ li9e thi!:
$L-+,-./#1in-pac&age#:com.gigamon&e?s.spam3 NOFhe#$;%.J9JI%;8M-H,.,TI%#pac&age/ ,TI%/#
5nce you h#?e # p#c9#ge de'ined, you c#n !t#rt on the #ctu#l code. &he *#in 'unction you@ll need to i*ple*ent h#! # !i*ple <ob--t#9e the te.t o' # *e!!#ge #! #n #rgu*ent #nd cl#!!i'y the *e!!#ge #! !p#*, h#*, or un!ure. 4ou c#n e#!ily i*ple*ent thi! b#!ic 'unction by de'ining it in ter*! o' other 'unction! th#t you@ll 6rite in # *o*ent.
1de('n#classi(?#1te)t3 ##1classi(ication#1score#1e)tract-(eat'res#te)t3333
$e#ding 'ro* the in!ide out, the 'ir!t !tep in cl#!!i'ying # *e!!#ge i! to e.tr#ct 'e#ture! to p#!! to the score 'unction. In score you@ll co*pute # ?#lue th#t c#n then be tr#n!l#ted into one o' three cl#!!i'ic#tion!--!p#*, h#*, or un!ure--by the 'unction classi(ication. 5' the three 'unction!, classi(ication i! the !i*ple!t. 4ou c#n #!!u*e score 6ill return # ?#lue ne#r 1 i' the *e!!#ge i! # !p#*, ne#r 0 i' it@! # h#*, #nd ne#r .5 i' it@! uncle#r. &hu!, you c#n i*ple*ent classi(ication li9e thi!:
1de(parameter#Uma)-ham-scoreU#.43 1de(parameter#Umin-spam-scoreU#.63 1de('n#classi(ication#1score3 ##1cond
&he e)tract-(eat'res 'unction i! #l*o!t #! !tr#ight'or6#rd, though it reFuire! # bit *ore code. /or the *o*ent, the 'e#ture! you@ll e.tr#ct 6ill be the 6ord! #ppe#ring in the te.t. /or e#ch 6ord, you need to 9eep tr#c9 o' the nu*ber o' ti*e! it h#! been !een in # !p#* #nd the nu*ber o' ti*e! it h#! been !een in # h#*. % con?enient 6#y to 9eep tho!e piece! o' d#t# together 6ith the 6ord it!el' i! to de'ine # cl#!!, word-(eat're, 6ith three !lot!.
1de(class#word-(eat're#13 ##11word####### ####:initarg#:word ####:accessor#word ####:init(orm#1error#4%'st#s'ppl?#:word43 ####:doc'mentation#4Fhe#word#this#(eat're#represents.43 ###1spam-co'nt ####:initarg#:spam-co'nt ####:accessor#spam-co'nt ####:init(orm# ####:doc'mentation#48'mber#o(#spams#we#have#seen#this#(eat're#in.43 ###1ham-co'nt ####:initarg#:ham-co'nt ####:accessor#ham-co'nt ####:init(orm# ####:doc'mentation#48'mber#o(#hams#we#have#seen#this#(eat're#in.4333
4ou@ll 9eep the d#t#b#!e o' 'e#ture! in # h#!h t#ble !o you c#n e#!ily 'ind the ob<ect repre!enting # gi?en 'e#ture. 4ou c#n de'ine # !peci#l ?#ri#ble, U(eat're-databaseU, to hold # re'erence to thi! h#!h t#ble.
1de(var#U(eat're-databaseU#1ma&e-hash-table#:test#NCe@'al33
4ou !hould u!e DEFVAR r#ther th#n DEFPARAMETER bec#u!e you don@t 6#nt U(eat'redatabaseU to be re!et i' you h#ppen to relo#d the 'ile cont#ining thi! de'inition during de?elop*ent--you *ight h#?e d#t# !tored in U(eat're-databaseU th#t you don@t 6#nt to lo!e. 5' cour!e, th#t *e#n! i' you do 6#nt to cle#r out the 'e#ture d#t#b#!e, you c#n@t <u!t ree?#lu#te the DEFVAR 'or*. So you !hould de'ine # 'unction clear-database.
1de('n#clear-database#13 ##1set(#U(eat're-databaseU#1ma&e-hash-table#:test#NCe@'al333
&o 'ind the 'e#ture! pre!ent in # gi?en *e!!#ge, the code 6ill need to e.tr#ct the indi?idu#l 6ord! #nd then loo9 up the corre!ponding word-(eat're ob<ect in U(eat're-databaseU. I' U(eat're-databaseU cont#in! no !uch 'e#ture, it@ll need to cre#te # ne6 word-(eat're to repre!ent the 6ord. 4ou c#n enc#p!ul#te th#t bit o' logic in # 'unction, intern-(eat're, th#t t#9e! # 6ord #nd return! the #ppropri#te 'e#ture, cre#ting it i' nece!!#ry.
1de('n#intern-(eat're#1word3 ##1or#1gethash#word#U(eat're-databaseU3 ######1set(#1gethash#word#U(eat're-databaseU3 ############1ma&e-instance#Cword-(eat're#:word#word3333
4ou c#n e.tr#ct the indi?idu#l 6ord! 'ro* the *e!!#ge te.t u!ing # regul#r e.pre!!ion. /or e.#*ple, u!ing the Co**on i!p Port#ble Perl-Co*p#tible $egul#r (.pre!!ion BC -PPC$(C libr#ry 6ritten by (di WeitA, you c#n 6rite e)tract-words li9e thi!:1de('n#e)tract-words#1te)t3 ##1delete-d'plicates ###1cl-ppcre:all-matches-as-strings#4Da-*I-^GV35W4#te)t3 ###:test#NCstring=33
:o6 #ll th#t re*#in! to i*ple*ent e)tract-(eat'res i! to put e)tract-(eat'res #nd intern-(eat're together. Since e)tract-words return! # li!t o' !tring! #nd you 6#nt # li!t 6ith e#ch !tring tr#n!l#ted to the corre!ponding word-(eat're, thi! i! # per'ect ti*e to u!e MAPCAR.
1de('n#e)tract-(eat'res#1te)t3 ##1mapcar#NCintern-(eat're#1e)tract-words#te)t333
%nd you c#n *#9e !ure the DELETE-DUPLICATES i! 6or9ing li9e thi!:
,TI%/#1e)tract-words#4(oo#bar#ba*#(oo#bar43 14ba*4#4(oo4#4bar43
>o6e?er, #! you c#n !ee, the de'#ult *ethod 'or printing #rbitr#ry ob<ect! i!n@t ?ery in'or*#ti?e. %! you 6or9 on thi! progr#*, it@ll be u!e'ul to be #ble to print word-(eat're ob<ect! in # le!! op#Fue 6#y. uc9ily, #! I *entioned in Ch#pter 12, the printing o' #ll ob<ect! i! i*ple*ented in ter*! o' # generic 'unction PRINT-OB4ECT, !o to ch#nge the 6#y word-(eat're ob<ect! #re printed, you <u!t need to de'ine # *ethod on PRINT-OB4ECT th#t !peci#liAe! on word-(eat're. &o *#9e i*ple*enting !uch *ethod! e#!ier, Co**on i!p pro?ide! the *#cro PRINT-UNREADABLEOB4ECT.5 &he b#!ic 'or* o' PRINT-UNREADABLE-OB4ECT i! #! 'ollo6!:
1print-'nreadable-object#1ob ect#stream-variable#>&e?#type#identity3 ##body-formU3
&he object #rgu*ent i! #n e.pre!!ion th#t e?#lu#te! to the ob<ect to be printed. Within the body o' PRINT-UNREADABLE-OB4ECT, stream)variable i! bound to # !tre#* to 6hich you c#n print #nything you 6#nt. Wh#te?er you print to th#t !tre#* 6ill be output by PRINT-UNREADABLEOB4ECT #nd enclo!ed in the !t#nd#rd !ynt#. 'or unre#d#ble ob<ect!, NO/.0 PRINT-UNREADABLE-OB4ECT #l!o let! you include the type o' the ob<ect #nd #n indic#tion o' the ob<ect@! identity ?i# the 9ey6ord p#r#*eter! t0pe #nd identit0. I' they@re non-NIL, the output 6ill !t#rt 6ith the n#*e o' the ob<ect@! cl#!! #nd end 6ith #n indic#tion o' the ob<ect@! identity !i*il#r to 6h#t@! printed by the de'#ult PRINT-OB4ECT *ethod 'or STANDARD-OB4ECT!. /or word-(eat're,
you prob#bly 6#nt to de'ine # PRINT-OB4ECT *ethod th#t include! the type but not the identity #long 6ith the ?#lue! o' the word, ham-co'nt, #nd spam-co'nt !lot!. Such # *ethod 6ould loo9 li9e thi!:
1de(method#print-object#11object#word-(eat're3#stream3 ##1print-'nreadable-object#1object#stream#:t?pe#t3 ####1with-slots#1word#ham-co'nt#spam-co'nt3#object ######1(ormat#stream#47s#:hams#7d#:spams#7d4#word#ham-co'nt#spam-co'nt3333
:o6 6hen you te!t e)tract-(eat'res #t the $(P , you c#n !ee *ore cle#rly 6h#t 'e#ture! #re being e.tr#cted.
,TI%/#1e)tract-(eat'res#4(oo#bar#ba*#(oo#bar43 1NOW;.<-E-IF+.-#4ba*4#:hams# #:spams# / #NOW;.<-E-IF+.-#4(oo4#:hams# #:spams# / #NOW;.<-E-IF+.-#4bar4#:hams# #:spams# /3
4ou@?e #lre#dy 6ritten e)tract-(eat'res, !o ne.t up i! increment-co'nt, 6hich t#9e! # word-(eat're #nd # *e!!#ge type #nd incre*ent! the #ppropri#te !lot o' the 'e#ture. Since there@! no re#!on to thin9 th#t the logic o' incre*enting the!e count! i! going to ch#nge 'or di''erent 9ind! o' ob<ect!, you c#n 6rite thi! #! # regul#r 'unction.2 7ec#u!e you de'ined both ham-co'nt #nd spamco'nt 6ith #n :accessor option, you c#n u!e INCF #nd the #cce!!or 'unction! cre#ted by DEFCLASS to incre*ent the #ppropri#te !lot.
1de('n#increment-co'nt#1(eat're#t?pe3 ##1ecase#t?pe ####1ham#1inc(#1ham-co'nt#(eat're333 ####1spam#1inc(#1spam-co'nt#(eat're33333
&he ECASE con!truct i! # ?#ri#nt o' CASE, both o' 6hich #re !i*il#r to case !t#te*ent! in %lgolderi?ed l#ngu#ge! Bren#*ed switch in C #nd it! progenyC. &hey both e?#lu#te their 'ir!t #rgu*ent-the $e0 form--#nd then 'ind the cl#u!e 6ho!e 'ir!t ele*ent--the $e0--i! the !#*e ?#lue #ccording to EQL. In thi! c#!e, th#t *e#n! the ?#ri#ble t?pe i! e?#lu#ted, yielding 6h#te?er ?#lue 6#! p#!!ed #! the !econd #rgu*ent to increment-co'nt. &he 9ey! #ren@t e?#lu#ted. In other 6ord!, the ?#lue o' t?pe 6ill be co*p#red to the liter#l ob<ect! re#d by the i!p re#der #! p#rt o' the ECASE 'or*. In thi! 'unction, th#t *e#n! the 9ey! #re the !y*bol! ham #nd spam, not the ?#lue! o' #ny ?#ri#ble! n#*ed ham #nd spam. So, i' incrementco'nt i! c#lled li9e thi!:
1increment-co'nt#some-(eat're#Cham3
the ?#lue o' t?pe 6ill be the !y*bol ham, #nd the 'ir!t br#nch o' the ECASE 6ill be e?#lu#ted #nd the 'e#ture@! h#* count incre*ented. 5n the other h#nd, i' it@! c#lled li9e thi!:
1increment-co'nt#some-(eat're#Cspam3
then the !econd br#nch 6ill run, incre*enting the !p#* count. :ote th#t the !y*bol! ham #nd spam #re Fuoted 6hen c#lling increment-co'nt !ince other6i!e they@d be e?#lu#ted #! the n#*e! o' ?#ri#ble!. 7ut they@re not Fuoted 6hen they #ppe#r in ECASE !ince ECASE doe!n@t e?#lu#te the 9ey!., &he + in ECASE !t#nd! 'or He.h#u!ti?eH or Herror,H *e#ning ECASE !hould !ign#l #n error i' the 9ey ?#lue i! #nything other th#n one o' the 9ey! li!ted. &he regul#r CASE i! loo!er, returning NIL i' no *#tching cl#u!e i! 'ound. &o i*ple*ent increment-total-co'nt, you need to decide 6here to !tore the count!G 'or the *o*ent, t6o *ore !peci#l ?#ri#ble!, Utotal-spamsU #nd Utotal-hamsU, 6ill do 'ine.
1de(var#Utotal-spamsU# 3 1de(var#Utotal-hamsU# 3 1de('n#increment-total-co'nt#1t?pe3 ##1ecase#t?pe ####1ham#1inc(#Utotal-hamsU33 ####1spam#1inc(#Utotal-spamsU3333
4ou !hould u!e DEFVAR to de'ine the!e t6o ?#ri#ble! 'or the !#*e re#!on you u!ed it 6ith U(eat're-databaseU--they@ll hold d#t# built up 6hile you run the progr#* th#t you don@t nece!!#rily 6#nt to thro6 #6#y <u!t bec#u!e you h#ppen to relo#d your code during de?elop*ent. 7ut you@ll 6#nt to re!et tho!e ?#ri#ble! i' you e?er re!et U(eat're-databaseU, !o you !hould #dd # 'e6 line! to clear-database #! !ho6n here:
1de('n#clear-database#13 ##1set( ###U(eat're-databaseU#1ma&e-hash-table#:test#NCe@'al3 ###Utotal-spamsU# ###Utotal-hamsU# 33
"er4Word /tatistics
&he he#rt o' # !t#ti!tic#l !p#* 'ilter i!, o' cour!e, the 'unction! th#t co*pute !t#ti!tic!-b#!ed prob#bilitie!. &he *#the*#tic#l nu#nce!) o' 6hy e.#ctly the!e co*put#tion! 6or9 #re beyond the !cope o' thi! boo9--intere!ted re#der! *#y 6#nt to re'er to !e?er#l p#per! by =#ry $obin!on.10 I@ll 'ocu! r#ther on ho6 they@re i*ple*ented. &he !t#rting point 'or the !t#ti!tic#l co*put#tion! i! the !et o' *e#!ured ?#lue!--the 'reFuencie! !tored in U(eat're-databaseU, Utotal-spamsU, #nd Utotal-hamsU. %!!u*ing th#t the !et o' *e!!#ge! tr#ined on i! !t#ti!tic#lly repre!ent#ti?e, you c#n tre#t the ob!er?ed 'reFuencie! #! prob#bilitie! o' the !#*e 'e#ture! !ho6ing up in h#*! #nd !p#*! in 'uture *e!!#ge!. &he b#!ic pl#n i! to cl#!!i'y # *e!!#ge by e.tr#cting the 'e#ture! it cont#in!, co*puting the indi?idu#l prob#bility th#t # gi?en *e!!#ge cont#ining the 'e#ture i! # !p#*, #nd then co*bining #ll the indi?idu#l prob#bilitie! into # tot#l !core 'or the *e!!#ge. 3e!!#ge! 6ith *#ny H!p#**yH 'e#ture! #nd 'e6
Hh#**yH 'e#ture! 6ill recei?e # !core ne#r 1, #nd *e!!#ge! 6ith *#ny h#**y 'e#ture! #nd 'e6 !p#**y 'e#ture! 6ill !core ne#r 0. &he 'ir!t !t#ti!tic#l 'unction you need i! one th#t co*pute! the b#!ic prob#bility th#t # *e!!#ge cont#ining # gi?en 'e#ture i! # !p#*. 7y one point o' ?ie6, the prob#bility th#t # gi?en *e!!#ge cont#ining the 'e#ture i! # !p#* i! the r#tio o' !p#* *e!!#ge! cont#ining the 'e#ture to #ll *e!!#ge! cont#ining the 'e#ture. &hu!, you could co*pute it thi! 6#y:
1de('n#spam-probabilit?#1(eat're3 ##1with-slots#1spam-co'nt#ham-co'nt3#(eat're ####1/#spam-co'nt#12#spam-co'nt#ham-co'nt3333
&he proble* 6ith the ?#lue co*puted by thi! 'unction i! th#t it@! !trongly #''ected by the o?er#ll prob#bility th#t an0 *e!!#ge 6ill be # !p#* or # h#*. /or in!t#nce, !uppo!e you get nine ti*e! #! *uch h#* #! !p#* in gener#l. % co*pletely neutr#l 'e#ture 6ill then #ppe#r in one !p#* 'or e?ery nine h#*!, gi?ing you # !p#* prob#bility o' 1;10 #ccording to thi! 'unction. 7ut you@re *ore intere!ted in the prob#bility th#t # gi?en 'e#ture 6ill #ppe#r in # !p#* *e!!#ge, independent o' the o?er#ll prob#bility o' getting # !p#* or h#*. &hu!, you need to di?ide the !p#* count by the tot#l nu*ber o' !p#*! tr#ined on #nd the h#* count by the tot#l nu*ber o' h#*!. &o #?oid di?i!ion-by-Aero error!, i' either o' Utotal-spamsU or Utotal-hamsU i! Aero, you !hould tre#t the corre!ponding 'reFuency #! Aero. B5b?iou!ly, i' the tot#l nu*ber o' either !p#*! or h#*! i! Aero, then the corre!ponding per-'e#ture count 6ill #l!o be Aero, !o you c#n tre#t the re!ulting 'reFuency #! Aero 6ithout ill e''ect.C
1de('n#spam-probabilit?#1(eat're3 ##1with-slots#1spam-co'nt#ham-co'nt3#(eat're ####1let#11spam-(re@'enc?#1/#spam-co'nt#1ma)#0#Utotal-spamsU333 ##########1ham-(re@'enc?#1/#ham-co'nt#1ma)#0#Utotal-hamsU3333 ######1/#spam-(re@'enc?#12#spam-(re@'enc?#ham-(re@'enc?33333
&hi! ?er!ion !u''er! 'ro* #nother proble*--it doe!n@t t#9e into #ccount the nu*ber o' *e!!#ge! #n#lyAed to #rri?e #t the per-6ord prob#bilitie!. Suppo!e you@?e tr#ined on 2,000 *e!!#ge!, h#l' !p#* #nd h#l' h#*. :o6 con!ider t6o 'e#ture! th#t h#?e #ppe#red only in !p#*!. 5ne h#! #ppe#red in #ll 1,000 !p#*!, 6hile the other #ppe#red only once. %ccording to the current de'inition o' spamprobabilit?, the #ppe#r#nce o' either 'e#ture predict! th#t # *e!!#ge i! !p#* 6ith eFu#l prob#bility, n#*ely, 1. >o6e?er, it@! !till Fuite po!!ible th#t the 'e#ture th#t h#! #ppe#red only once i! #ctu#lly # neutr#l 'e#ture--it@! ob?iou!ly r#re in either !p#*! or h#*!, #ppe#ring only once in 2,000 *e!!#ge!. I' you tr#ined on #nother 2,000 *e!!#ge!, it *ight ?ery 6ell #ppe#r one *ore ti*e, thi! ti*e in # h#*, *#9ing it !uddenly # neutr#l 'e#ture 6ith # !p#* prob#bility o' .5. So it !ee*! you *ight li9e to co*pute # prob#bility th#t !o*eho6 '#ctor! in the nu*ber o' d#t# point! th#t go into e#ch 'e#ture@! prob#bility. In hi! p#per!, $obin!on !ugge!ted # 'unction b#!ed on the 7#ye!i#n notion o' incorpor#ting ob!er?ed d#t# into prior 9no6ledge or #!!u*ption!. 7#!ic#lly, you c#lcul#te # ne6 prob#bility by !t#rting 6ith #n #!!u*ed prior prob#bility #nd # 6eight to gi?e th#t #!!u*ed prob#bility be'ore #dding ne6 in'or*#tion. $obin!on@! 'unction i! thi!:
1de('n#ba?esian-spam-probabilit?#1(eat're#>optional ##################################1ass'med-probabilit?#0/!3 ##################################1weight#033 ##1let#11basic-probabilit?#1spam-probabilit?#(eat're33 ########1data-points#12#1spam-co'nt#(eat're3#1ham-co'nt#(eat're3333 ####1/#12#1U#weight#ass'med-probabilit?3
##########1U#data-points#basic-probabilit?33 #######12#weight#data-points3333
$obin!on !ugge!t! ?#lue! o' 1;2 'or ass'med-probabilit? #nd 1 'or weight. 8!ing tho!e ?#lue!, # 'e#ture th#t h#! #ppe#red in one !p#* #nd no h#*! h#! # ba?esian-spamprobabilit? o' 0.25, # 'e#ture th#t h#! #ppe#red in 10 !p#*! #nd no h#*! h#! # ba?esianspam-probabilit? o' #ppro.i*#tely 0.)55, #nd one th#t h#! *#tched in 1,000 !p#*! #nd no h#*! h#! # !p#* prob#bility o' #ppro.i*#tely 0.)))5.
#o$2ining "ro2a2i%ities
:o6 th#t you c#n co*pute the ba?esian-spam-probabilit? o' e#ch indi?idu#l 'e#ture you 'ind in # *e!!#ge, the l#!t !tep in i*ple*enting the score 'unction i! to 'ind # 6#y to co*bine # bunch o' indi?idu#l prob#bilitie! into # !ingle ?#lue bet6een 0 #nd 1. I' the indi?idu#l 'e#ture prob#bilitie! 6ere independent, then it@d be *#the*#tic#lly !ound to *ultiply the* together to get # co*bined prob#bility. 7ut it@! unli9ely they #ctu#lly #re independent--cert#in 'e#ture! #re li9ely to #ppe#r together, 6hile other! ne?er do.11 $obin!on propo!ed u!ing # *ethod 'or co*bining prob#bilitie! in?ented by the !t#ti!tici#n $. %. /i!her. Without going into the det#il! o' e.#ctly 6hy hi! techniFue 6or9!, it@! thi!: /ir!t you co*bine the prob#bilitie! by *ultiplying the* together. &hi! gi?e! you # nu*ber ne#rer to 0 the *ore lo6 prob#bilitie! there 6ere in the origin#l !et. &hen t#9e the log o' th#t nu*ber #nd *ultiply by -2. /i!her !ho6ed in 1)50 th#t i' the indi?idu#l prob#bilitie! 6ere independent #nd dr#6n 'ro* # uni'or* di!tribution bet6een 0 #nd 1, then the re!ulting ?#lue 6ould be on # chi-!Fu#re di!tribution. &hi! ?#lue #nd t6ice the nu*ber o' prob#bilitie! c#n be 'ed into #n in?er!e chi-!Fu#re 'unction, #nd it@ll return the prob#bility th#t re'lect! the li9elihood o' obt#ining # ?#lue th#t l#rge or l#rger by co*bining the !#*e nu*ber o' r#ndo*ly !elected prob#bilitie!. When the in?er!e chi-!Fu#re 'unction return! # lo6 prob#bility, it *e#n! there 6#! # di!proportion#te nu*ber o' lo6 prob#bilitie! Beither # lot o' rel#ti?ely lo6 prob#bilitie! or # 'e6 ?ery lo6 prob#bilitie!C in the indi?idu#l prob#bilitie!. &o u!e thi! prob#bility in deter*ining 6hether # gi?en *e!!#ge i! # !p#*, you !t#rt 6ith # null h0pothesis, # !tr#6 *#n you hope to 9noc9 do6n. &he null hypothe!i! i! th#t the *e!!#ge being cl#!!i'ied i! in '#ct <u!t # r#ndo* collection o' 'e#ture!. I' it 6ere, then the indi?idu#l prob#bilitie!--the li9elihood th#t e#ch 'e#ture 6ould #ppe#r in # !p#*--6ould #l!o be r#ndo*. &h#t i!, # r#ndo* !election o' 'e#ture! 6ould u!u#lly cont#in !o*e 'e#ture! 6ith # high prob#bility o' #ppe#ring in !p#* #nd other 'e#ture! 6ith # lo6 prob#bility o' #ppe#ring in !p#*. I' you 6ere to co*bine the!e r#ndo*ly !elected prob#bilitie! #ccording to /i!her@! *ethod, you !hould get # *iddling co*bined ?#lue, 6hich the in?er!e chi-!Fu#re 'unction 6ill tell you i! Fuite li9ely to #ri!e <u!t by ch#nce, #!, in '#ct, it 6ould h#?e. 7ut i' the in?er!e chi-!Fu#re 'unction return! # ?ery lo6 prob#bility, it *e#n! it@! unli9ely the prob#bilitie! th#t 6ent into the co*bined ?#lue 6ere !elected #t r#ndo*G there 6ere too *#ny lo6 prob#bilitie! 'or th#t to be li9ely. So you c#n re<ect the null hypothe!i! #nd in!te#d #dopt the #ltern#ti?e hypothe!i! th#t the 'e#ture! in?ol?ed 6ere dr#6n 'ro* # bi#!ed !#*ple--one 6ith 'e6 high !p#* prob#bility 'e#ture! #nd *#ny lo6 !p#* prob#bility 'e#ture!. In other 6ord!, it *u!t be # h#* *e!!#ge. >o6e?er, the /i!her *ethod i!n@t !y**etric#l !ince the in?er!e chi-!Fu#re 'unction return! the prob#bility th#t # gi?en nu*ber o' r#ndo*ly !elected prob#bilitie! 6ould co*bine to # ?#lue #! l#rge or l#rger th#n the one you got by co*bining the #ctu#l prob#bilitie!. &hi! #!y**etry 6or9! to your #d?#nt#ge bec#u!e 6hen you re<ect the null hypothe!i!, you 9no6 6h#t the *ore li9ely hypothe!i! i!. When you co*bine the indi?idu#l !p#* prob#bilitie! ?i# the /i!her *ethod, #nd it tell! you there@! # high prob#bility th#t the null hypothe!i! i! 6rong--th#t the *e!!#ge i!n@t # r#ndo* collection o' 6ord!--
then it *e#n! it@! li9ely the *e!!#ge i! # h#*. &he nu*ber returned i!, i' not liter#lly the prob#bility th#t the *e!!#ge i! # h#*, #t le#!t # good *e#!ure o' it! Hh#**ine!!.H Con?er!ely, the /i!her co*bin#tion o' the indi?idu#l h#* prob#bilitie! gi?e! you # *e#!ure o' the *e!!#ge@! H!p#**ine!!.H &o get # 'in#l !core, you need to co*bine tho!e t6o *e#!ure! into # !ingle nu*ber th#t gi?e! you # co*bined h#**ine!!-!p#**ine!! !core r#nging 'ro* 0 to 1. &he *ethod reco**ended by $obin!on i! to #dd h#l' the di''erence bet6een the h#**ine!! #nd !p#**ine!! !core! to 1;2, in other 6ord!, to #?er#ge the !p#**ine!! #nd 1 *inu! the h#**ine!!. &hi! h#! the nice e''ect th#t 6hen the t6o !core! #gree Bhigh !p#**ine!! #nd lo6 h#**ine!!, or ?ice ?er!#C you@ll end up 6ith # !trong indic#tor ne#r either 0 or 1. 7ut 6hen the !p#**ine!! #nd h#**ine!! !core! #re both high or both lo6, then you@ll end up 6ith # 'in#l ?#lue ne#r 1;2, 6hich you c#n tre#t #! #n Huncert#inH cl#!!i'ic#tion. &he score 'unction th#t i*ple*ent! thi! !che*e loo9! li9e thi!:
1de('n#score#1(eat'res3 ##1let#11spam-probs#133#1ham-probs#133#1n'mber-o(-probs# 33 ####1dolist#1(eat're#(eat'res3 ######1'nless#1'ntrained-p#(eat're3 ########1let#11spam-prob#1(loat#1ba?esian-spam-probabilit?#(eat're3# . d 333 ##########1p'sh#spam-prob#spam-probs3 ##########1p'sh#1-#0. d #spam-prob3#ham-probs3 ##########1inc(#n'mber-o(-probs3333 ####1let#11h#1-#0#1(isher#spam-probs#n'mber-o(-probs333 ##########1s#1-#0#1(isher#ham-probs#n'mber-o(-probs3333 ######1/#12#1-#0#h3#s3#!. d 3333
4ou t#9e # li!t o' 'e#ture! #nd loop o?er the*, building up t6o li!t! o' prob#bilitie!, one li!ting the prob#bilitie! th#t # *e!!#ge cont#ining e#ch 'e#ture i! # !p#* #nd the other th#t # *e!!#ge cont#ining e#ch 'e#ture i! # h#*. %! #n opti*iA#tion, you c#n #l!o count the nu*ber o' prob#bilitie! 6hile looping o?er the* #nd p#!! the count to (isher to #?oid h#?ing to count the* #g#in in (isher it!el'. &he ?#lue returned by (isher 6ill be lo6 i' the indi?idu#l prob#bilitie! cont#ined too *#ny lo6 prob#bilitie! to h#?e co*e 'ro* r#ndo* te.t. &hu!, # lo6 (isher !core 'or the !p#* prob#bilitie! *e#n! there 6ere *#ny h#**y 'e#ture!G !ubtr#cting th#t !core 'ro* 1 gi?e! you # prob#bility th#t the *e!!#ge i! # h#*. Con?er!ely, !ubtr#cting the (isher !core 'or the h#* prob#bilitie! gi?e! you the prob#bility th#t the *e!!#ge 6#! # !p#*. Co*bining tho!e t6o prob#bilitie! gi?e! you #n o?er#ll !p#**ine!! !core bet6een 0 #nd 1. Within the loop, you c#n u!e the 'unction 'ntrained-p to !9ip 'e#ture! e.tr#cted 'ro* the *e!!#ge th#t 6ere ne?er !een during tr#ining. &he!e 'e#ture! 6ill h#?e !p#* count! #nd h#* count! o' Aero. &he 'ntrained-p 'unction i! tri?i#l.
1de('n#'ntrained-p#1(eat're3 ##1with-slots#1spam-co'nt#ham-co'nt3#(eat're ####1and#1*erop#spam-co'nt3#1*erop#ham-co'nt3333
&he only other ne6 'unction i! (isher it!el'. %!!u*ing you #lre#dy h#d #n inverse-chis@'are 'unction, (isher i! conceptu#lly !i*ple.
1de('n#(isher#1probs#n'mber-o(-probs3 ##4Fhe#Eisher#comp'tation#described#b?#.obinson.4 ##1inverse-chi-s@'are# ###1U#-!#1log#1red'ce#NCU#probs333 ###1U#!#n'mber-o(-probs333
8n'ortun#tely, there@! # !*#ll proble* 6ith thi! !tr#ight'or6#rd i*ple*ent#tion. While u!ing REDUCE
i! # conci!e #nd idio*#tic 6#y o' *ultiplying # li!t o' nu*ber!, in thi! p#rticul#r #pplic#tion there@! # d#nger the product 6ill be too !*#ll # nu*ber to be repre!ented #! # 'lo#ting-point nu*ber. In th#t c#!e, the re!ult 6ill underflow to Aero. %nd i' the product o' the prob#bilitie! under'lo6!, #ll bet! #re o'' bec#u!e t#9ing the LOG o' Aero 6ill either !ign#l #n error or, in !o*e i*ple*ent#tion, re!ult in # !peci#l neg#ti?e-in'inity ?#lue, 6hich 6ill render #ll !ub!eFuent c#lcul#tion! e!!enti#lly *e#ningle!!. &hi! i! p#rticul#rly un'ortun#te in thi! 'unction bec#u!e the /i!her *ethod i! *o!t !en!iti?e 6hen the input prob#bilitie! #re lo6--ne#r Aero--#nd there'ore in the *o!t d#nger o' c#u!ing the *ultiplic#tion to under'lo6. uc9ily, you c#n u!e # bit o' high-!chool *#th to #?oid thi! proble*. $ec#ll th#t the log o' # product i! the !#*e #! the !u* o' the log! o' the '#ctor!. So in!te#d o' *ultiplying #ll the prob#bilitie! #nd then t#9ing the log, you c#n !u* the log! o' e#ch prob#bility. %nd !ince REDUCE t#9e! # :&e? 9ey6ord p#r#*eter, you c#n u!e it to per'or* the 6hole c#lcul#tion. In!te#d o' thi!:
1log#1red'ce#NCU#probs33
6rite thi!:
1red'ce#NC2#probs#:&e?#NClog3
$ec#ll 'ro* Ch#pter 10 th#t EXP r#i!e! e to the #rgu*ent gi?en. &hu!, the l#rger val'e i!, the !*#ller the initi#l ?#lue o' prob 6ill be. 7ut th#t initi#l ?#lue 6ill then be #d<u!ted up6#rd !lightly 'or e#ch degree o' 'reedo* #! long #! m i! gre#ter th#n the nu*ber o' degree! o' 'reedo*. Since the ?#lue returned by inverse-chi-s@'are i! !uppo!ed to be #nother prob#bility, it@! i*port#nt to cl#*p the ?#lue returned 6ith MIN !ince rounding error! in the *ultiplic#tion #nd e.ponenti#tion *#y c#u!e the LOOP to return # !u* <u!t # !h#de o?er 1.
While ulti*#tely #ll you c#re #bout i! the cl#!!i'ic#tion, it@d be nice to be #ble to !ee the r#6 !core too. &he e#!ie!t 6#y to get both ?#lue! 6ithout di!turbing #ny other code i! to ch#nge classi(ication to return *ultiple ?#lue!.
1de('n#classi(ication#1score3 ##1val'es ###1cond #####11O=#score#Uma)-ham-scoreU3#Cham3 #####11/=#score#Umin-spam-scoreU3#Cspam3 #####1t#C'ns're33 ###score33
4ou c#n *#9e thi! ch#nge #nd then reco*pile <u!t thi! one 'unction. 7ec#u!e classi(? return! 6h#te?er classi(ication return!, it@ll #l!o no6 return t6o ?#lue!. 7ut !ince the pri*#ry return ?#lue i! the !#*e, c#ller! o' either 'unction 6ho e.pect only one ?#lue 6on@t be #''ected. :o6 6hen you te!t classi(?, you c#n !ee e.#ctly 6h#t !core 6ent into the cl#!!i'ic#tion.
,TI%/#1classi(?#4%a&e#mone?#(ast43 ,TI% .R636QQ0 0R"4!Q3< ,TI%/#1classi(?#4Want#to#go#to#the#movies?43 +8,+.."<
%nd no6 you c#n !ee 6h#t h#ppen! i' you tr#in the 'ilter 6ith !o*e *ore h#* te.t.
,TI%/#1train#4<o#?o'#have#an?#mone?#(or#the#movies?4#Cham3 0 ,TI%/#1classi(?#4%a&e#mone?#(ast43 ,TI% .Q6R"3"0!09R"Q6!6<
It@! !till !p#* but # bit le!! cert#in !ince mone0 6#! !een in h#* te.t.
%nd no6 thi! i! cle#rly recogniA#ble h#* th#n9! to the pre!ence o' the 6ord movies, no6 # h#**y 'e#ture. >o6e?er, you don@t re#lly 6#nt to tr#in the 'ilter by h#nd. Wh#t you@d re#lly li9e i! #n e#!y 6#y to point it #t # bunch o' 'ile! #nd tr#in it on the*. %nd i' you 6#nt to te!t ho6 6ell the 'ilter #ctu#lly 6or9!, you@d li9e to then u!e it to cl#!!i'y #nother !et o' 'ile! o' 9no6n type! #nd !ee ho6 it doe!. So the l#!t bit o' code you@ll 6rite in thi! ch#pter 6ill be # te!t h#rne!! th#t te!t! the 'ilter on # corpu! o' *e!!#ge! o' 9no6n type!, u!ing # cert#in 'r#ction 'or tr#ining #nd then *e#!uring ho6 #ccur#te the 'ilter i! 6hen cl#!!i'ying the re*#inder.
&he ?#lue o' corp's !hould be #n #d<u!t#ble ?ector 6ith # 'ill pointer. /or in!t#nce, you c#n *#9e # ne6 corpu! li9e thi!:
1de(parameter#Ucorp'sU#1ma&e-arra?#0 #:adj'stable#t#:(ill-pointer# 33
I' you h#?e the h#*! #nd !p#*! #lre#dy !egreg#ted into !ep#r#te directorie!, you *ight 6#nt to #dd #ll the 'ile! in # directory #! the !#*e type. &hi! 'unction, 6hich u!e! the list-director? 'unction 'ro* Ch#pter 15, 6ill do the tric9:
1de('n#add-director?-to-corp's#1dir#t?pe#corp's3 ##1dolist#1(ilename#1list-director?#dir33 ####1add-(ile-to-corp's#(ilename#t?pe#corp's333
/or in!t#nce, !uppo!e you h#?e # directory mail cont#ining t6o !ubdirectorie!, spam #nd ham, e#ch cont#ining *e!!#ge! o' the indic#ted typeG you c#n #dd #ll the 'ile! in tho!e t6o directorie! to Ucorp'sU li9e thi!:
,TI%/#1add-director?-to-corp's#4mail/spam/4#Cspam#Ucorp'sU3 89L ,TI%/#1add-director?-to-corp's#4mail/ham/4#Cham#Ucorp'sU3 89L
:o6 you need # 'unction to te!t the cl#!!i'ier. &he b#!ic !tr#tegy 6ill be to !elect # r#ndo* chun9 o' the corpu! to tr#in on #nd then te!t the corpu! by cl#!!i'ying the re*#inder o' the corpu!, co*p#ring the cl#!!i'ic#tion returned by the classi(? 'unction to the 9no6n cl#!!i'ic#tion. &he *#in thing you 6#nt to 9no6 i! ho6 #ccur#te the cl#!!i'ier i!--6h#t percent#ge o' the *e!!#ge! #re cl#!!i'ied correctly" 7ut you@ll prob#bly #l!o be intere!ted in 6h#t *e!!#ge! 6ere *i!cl#!!i'ied #nd in 6h#t
direction--6ere there *ore '#l!e po!iti?e! or *ore '#l!e neg#ti?e!" &o *#9e it e#!y to per'or* di''erent #n#ly!e! o' the cl#!!i'ier@! beh#?ior, you !hould de'ine the te!ting 'unction! to build # li!t o' r#6 re!ult!, 6hich you c#n then #n#lyAe ho6e?er you li9e. &he *#in te!ting 'unction *ight loo9 li9e thi!:
1de('n#test-classi(ier#1corp's#testing-(raction3 ##1clear-database3 ##1letU#11sh'((led#1sh'((le-vector#corp's33 #########1si*e#1length#corp's33 #########1train-on#1(loor#1U#si*e#1-#0#testing-(raction33333 ####1train-(rom-corp's#sh'((led#:start# #:end#train-on3 ####1test-(rom-corp's#sh'((led#:start#train-on333
&hi! 'unction !t#rt! by cle#ring out the 'e#ture d#t#b#!e.13 &hen it !hu''le! the corpu!, u!ing # 'unction you@ll i*ple*ent in # *o*ent, #nd 'igure! out, b#!ed on the testing-(raction p#r#*eter, ho6 *#ny *e!!#ge! it@ll tr#in on #nd ho6 *#ny it@ll re!er?e 'or te!ting. &he t6o helper 'unction! train(rom-corp's #nd test-(rom-corp's 6ill both t#9e :start #nd :end 9ey6ord p#r#*eter!, #llo6ing the* to oper#te on # !ub!eFuence o' the gi?en corpu!. &he train-(rom-corp's 'unction i! Fuite !i*ple--!i*ply loop o?er the #ppropri#te p#rt o' the corpu!, u!e DESTRUCTURING-BIND to e.tr#ct the 'ilen#*e #nd type 'ro* the li!t 'ound in e#ch ele*ent, #nd then p#!! the te.t o' the n#*ed 'ile #nd the type to train. Since !o*e *#il *e!!#ge!, !uch #! tho!e 6ith #tt#ch*ent!, #re Fuite l#rge, you !hould li*it the nu*ber o' ch#r#cter! it@ll t#9e 'ro* the *e!!#ge. It@ll obt#in the te.t 6ith # 'unction start-o(-(ile, 6hich you@ll i*ple*ent in # *o*ent, th#t t#9e! # 'ilen#*e #nd # *#.i*u* nu*ber o' ch#r#cter! to return. train-(romcorp's loo9! li9e thi!:
1de(parameter#Uma)-charsU#1U#0 #0 !433 1de('n#train-(rom-corp's#1corp's#>&e?#1start# 3#end3 ##1loop#(or#id)#(rom#start#below#1or#end#1length#corp's33#do ########1destr'ct'ring-bind#1(ile#t?pe3#1are(#corp's#id)3 ##########1train#1start-o(-(ile#(ile#Uma)-charsU3#t?pe3333
&he test-(rom-corp's 'unction i! !i*il#r e.cept you 6#nt to return # li!t cont#ining the re!ult! o' e#ch cl#!!i'ic#tion !o you c#n #n#lyAe the* #'ter the '#ct. &hu!, you !hould c#pture both the cl#!!i'ic#tion #nd !core returned by classi(? #nd then collect # li!t o' the 'ilen#*e, the #ctu#l type, the type returned by classi(?, #nd the !core. &o *#9e the re!ult! *ore hu*#n re#d#ble, you c#n include 9ey6ord! in the li!t to indic#te 6hich ?#lue! #re 6hich.
1de('n#test-(rom-corp's#1corp's#>&e?#1start# 3#end3 ##1loop#(or#id)#(rom#start#below#1or#end#1length#corp's33#collect ########1destr'ct'ring-bind#1(ile#t?pe3#1are(#corp's#id)3 ##########1m'ltiple-val'e-bind#1classi(ication#score3 ##############1classi(?#1start-o(-(ile#(ile#Uma)-charsU33 ############1list# #############:(ile#(ile #############:t?pe#t?pe #############:classi(ication#classi(ication #############:score#score33333
&he nonde!tructi?e ?er!ion !i*ply *#9e! # copy o' the origin#l ?ector #nd p#!!e! it to the de!tructi?e ?er!ion.
1de('n#sh'((le-vector#1vector3 ##1nsh'((le-vector#1cop?-se@#vector333
&he other utility 'unction, start-o(-(ile, i! #l*o!t #! !tr#ight'or6#rd 6ith <u!t one 6rin9le. &he *o!t e''icient 6#y to re#d the content! o' # 'ile into *e*ory i! to cre#te #n #rr#y o' the #ppropri#te !iAe #nd u!e READ-SEQUENCE to 'ill it in. So it *ight !ee* you could *#9e # ch#r#cter #rr#y th#t@! either the !iAe o' the 'ile or the *#.i*u* nu*ber o' ch#r#cter! you 6#nt to re#d, 6hiche?er i! !*#ller. 8n'ortun#tely, #! I *entioned in Ch#pter 1-, the 'unction FILE-LENGTH i!n@t entirely 6ell de'ined 6hen de#ling 6ith ch#r#cter !tre#*! !ince the nu*ber o' ch#r#cter! encoded in # 'ile c#n depend on both the ch#r#cter encoding u!ed #nd the p#rticul#r te.t in the 'ile. In the 6or!t c#!e, the only 6#y to get #n #ccur#te *e#!ure o' the nu*ber o' ch#r#cter! in # 'ile i! to #ctu#lly re#d the 6hole 'ile. &hu!, it@! #*biguou! 6h#t FILE-LENGTH !hould do 6hen p#!!ed # ch#r#cter !tre#*G in *o!t i*ple*ent#tion!, FILE-LENGTH #l6#y! return! the nu*ber o' octet! in the 'ile, 6hich *#y be gre#ter th#n the nu*ber o' ch#r#cter! th#t c#n be re#d 'ro* the 'ile. >o6e?er, READ-SEQUENCE return! the nu*ber o' ch#r#cter! #ctu#lly re#d. So, you c#n #tte*pt to re#d the nu*ber o' ch#r#cter! reported by FILE-LENGTH #nd return # !ub!tring i' the #ctu#l nu*ber o' ch#r#cter! re#d 6#! !*#ller.
1de('n#start-o(-(ile#1(ile#ma)-chars3 ##1with-open-(ile#1in#(ile3 ####1letU#11length#1min#1(ile-length#in3#ma)-chars33 ###########1te)t#1ma&e-string#length33 ###########1read#1read-se@'ence#te)t#in333 ######1i(#1O#read#length3 ########1s'bse@#te)t# #read3 ########te)t3333
i! # pli!t repre!enting the re!ult o' cl#!!i'ying one 'ile. &hi! pli!t cont#in! the n#*e o' the 'ile, the #ctu#l type o' the 'ile, the cl#!!i'ic#tion, #nd the !core returned by classi(?. &he 'ir!t bit o' #n#lytic#l code you !hould 6rite i! # 'unction th#t return! # !y*bol indic#ting 6hether # gi?en re!ult 6#! correct, # '#l!e po!iti?e, # '#l!e neg#ti?e, # *i!!ed h#*, or # *i!!ed !p#*. 4ou c#n u!e DESTRUCTURING-BIND to pull out the :t?pe #nd :classi(ication ele*ent! o' #n indi?idu#l re!ult li!t Bu!ing &$%%o5-o!6'&-)'*( to tell DESTRUCTURING-BIND to ignore #ny other 9ey;?#lue p#ir! it !ee!C #nd then u!e ne!ted ECASE to tr#n!l#te the di''erent p#iring! into # !ingle !y*bol.
1de('n#res'lt-t?pe#1res'lt3 ##1destr'ct'ring-bind#1>&e?#t?pe#classi(ication#>allow-other-&e?s3#res'lt ####1ecase#t?pe ######1ham #######1ecase#classi(ication #########1ham#Ccorrect3 #########1spam#C(alse-positive3 #########1'ns're#Cmissed-ham333 ######1spam #######1ecase#classi(ication #########1ham#C(alse-negative3 #########1spam#Ccorrect3 #########1'ns're#Cmissed-spam333333
>#?ing thi! 'unction *#9e! it e#!y to !lice #nd dice the re!ult! o' test-classi(ier in # ?#riety o' 6#y!. /or in!t#nce, you c#n !t#rt by de'ining predic#te 'unction! 'or e#ch type o' re!ult.
1de('n#(alse-positive-p#1res'lt3 ##1e@l#1res'lt-t?pe#res'lt3#C(alse-positive33 1de('n#(alse-negative-p#1res'lt3 ##1e@l#1res'lt-t?pe#res'lt3#C(alse-negative33 1de('n#missed-ham-p#1res'lt3 ##1e@l#1res'lt-t?pe#res'lt3#Cmissed-ham33 1de('n#missed-spam-p#1res'lt3 ##1e@l#1res'lt-t?pe#res'lt3#Cmissed-spam33 1de('n#correct-p#1res'lt3 ##1e@l#1res'lt-t?pe#res'lt3#Ccorrect33
With tho!e 'unction!, you c#n e#!ily u!e the li!t #nd !eFuence *#nipul#tion 'unction! I di!cu!!ed in Ch#pter 11 to e.tr#ct #nd count p#rticul#r 9ind! o' re!ult!.
,TI%/#1co'nt-i(#NC(alse-positive-p#Ures'ltsU3 6 ,TI%/#1remove-i(-not#NC(alse-positive-p#Ures'ltsU3 11:E9L-#Np4ham/"3494#:FHT-#:I%#:$LI,,9E9$IF9;8#,TI%#:,$;.-# .99999R30 Q3"""40d 3 #1:E9L-#Np4ham/!Q464#:FHT-#:I%#:$LI,,9E9$IF9;8#,TI%#:,$;.-# .6!R646R9"6609Q9"d 3 #1:E9L-#Np4ham/34!Q4#:FHT-#:I%#:$LI,,9E9$IF9;8#,TI%#:,$;.-# .9R33Q"3" 03"!9R3d 3 #1:E9L-#Np4ham/QQR"4#:FHT-#:I%#:$LI,,9E9$IF9;8#,TI%#:,$;.-# .9"4!QRR"RQ99R4RRd 3 #1:E9L-#Np4ham/0Q!R4#:FHT-#:I%#:$LI,,9E9$IF9;8#,TI%#:,$;.-# .6R433906!R90!60d 3 #1:E9L-#Np4ham/0 "R04#:FHT-#:I%#:$LI,,9E9$IF9;8#,TI%#:,$;.-# .99999!4"3Q9"960"d 33
4ou c#n #l!o u!e the !y*bol! returned by res'lt-t?pe #! 9ey! into # h#!h t#ble or #n #li!t. /or in!t#nce, you c#n 6rite # 'unction to print # !u**#ry o' the count! #nd percent#ge! o' e#ch type o' re!ult u!ing #n #li!t th#t *#p! e#ch type plu! the e.tr# !y*bol total to # count.
1de('n#anal?*e-res'lts#1res'lts3 ##1letU#11&e?s#C1total#correct#(alse-positive# #################(alse-negative#missed-ham#missed-spam33 #########1co'nts#1loop#(or#)#in#&e?s#collect#1cons#)# 3333 ####1dolist#1item#res'lts3 ######1inc(#1cdr#1assoc#Ctotal#co'nts333 ######1inc(#1cdr#1assoc#1res'lt-t?pe#item3#co'nts3333 ####1loop#with#total#=#1cdr#1assoc#Ctotal#co'nts33 ##########(or#1label#.#co'nt3#in#co'nts ##########do#1(ormat#t#47>7P17a73:7! t7"d75"t:#765!(6764 #####################label#co'nt#1U#0 #1/#co'nt#total333333
&hi! 'unction 6ill gi?e output li9e thi! 6hen p#!!ed # li!t o' re!ult! gener#ted by testclassi(ier:
,TI%/#1anal?*e-res'lts#Ures'ltsU3 Fotal:###############3Q60#:#0 . 6 $orrect:#############36R9#:##9R. 96 Ealse-positive:#########4#:### .006 Ealse-negative:#########9#:### .!46 %issed-ham:############09#:### ."06 %issed-spam:###########4 #:###0. 66 89L
%nd #! # l#!t bit o' #n#ly!i! you *ight 6#nt to loo9 #t 6hy #n indi?idu#l *e!!#ge 6#! cl#!!i'ied the 6#y it 6#!. &he 'ollo6ing 'unction! 6ill !ho6 you:
1de('n#e)plain-classi(ication#1(ile3 ##1letU#11te)t#1start-o(-(ile#(ile#Uma)-charsU33 #########1(eat'res#1e)tract-(eat'res#te)t33 #########1score#1score#(eat'res33 #########1classi(ication#1classi(ication#score333 ####1show-s'mmar?#(ile#te)t#classi(ication#score3 ####1dolist#1(eat're#1sorted-interesting#(eat'res33 ######1show-(eat're#(eat're3333 1de('n#show-s'mmar?#1(ile#te)t#classi(ication#score3 ##1(ormat#t#47>7a4#(ile3 ##1(ormat#t#47!67a7!64#te)t3 ##1(ormat#t#4$lassi(ied#as#7a#with#score#o(#75"(764#classi(ication#score33
What6s :e)t
5b?iou!ly, you could do # lot *ore 6ith thi! code. &o turn it into # re#l !p#*-'iltering #pplic#tion, you@d need to 'ind # 6#y to integr#te it into your nor*#l e-*#il in'r#!tructure. 5ne #ppro#ch th#t 6ould *#9e it e#!y to integr#te 6ith #l*o!t #ny e-*#il client i! to 6rite # bit o' code to #ct #! # P5P3 pro.y-th#t@! the protocol *o!t e-*#il client! u!e to 'etch *#il 'ro* *#il !er?er!. Such # pro.y 6ould 'etch *#il 'ro* your re#l P5P3 !er?er #nd !er?e it to your *#il client #'ter either t#gging !p#* 6ith # he#der th#t your e-*#il client@! 'ilter! c#n e#!ily recogniAe or !i*ply putting it #!ide. 5' cour!e, you@d #l!o need # 6#y to co**unic#te 6ith the 'ilter #bout *i!cl#!!i'ic#tion!--#! long #! you@re !etting it up #! # !er?er, you could #l!o pro?ide # Web inter'#ce. I@ll t#l9 #bout ho6 to 6rite Web inter'#ce! in Ch#pter 20, #nd you@ll build one, 'or # di''erent #pplic#tion, in Ch#pter 2). 5r you *ight 6#nt to 6or9 on i*pro?ing the b#!ic cl#!!i'ic#tion--# li9ely pl#ce to !t#rt i! to *#9e e)tract-(eat'res *ore !ophi!tic#ted. In p#rticul#r, you could *#9e the to9eniAer !*#rter #bout the intern#l !tructure o' e-*#il--you could e.tr#ct di''erent 9ind! o' 'e#ture! 'or 6ord! #ppe#ring in the body ?er!u! the *e!!#ge he#der!. %nd you could decode ?#riou! 9ind! o' *e!!#ge encoding !uch #! b#!e 0- #nd Fuoted print#ble !ince !p#**er! o'ten try to ob'u!c#te their *e!!#ge 6ith tho!e encoding!. 7ut I@ll le#?e tho!e i*pro?e*ent! to you. :o6 you@re re#dy to he#d do6n the p#th o' building # !tre#*ing 3P3 !er?er, !t#rting by 6riting # gener#l-purpo!e libr#ry 'or p#r!ing bin#ry 'ile!.
1%?#il#ble 2&here
#t http://www.pa'lgraham.com/spam.html #nd #l!o in Bac$ers C Painters: #ig ;deas from the Computer !ge B5@$eilly, 200-C h#! !ince been !o*e di!#gree*ent o?er 6hether the techniFue =r#h#* de!cribed 6#! #ctu#lly H7#ye!i#n.H >o6e?er, the n#*e h#! !tuc9 #nd i! 6ell on it! 6#y to beco*ing # !ynony* 'or H!t#ti!tic#lH 6hen t#l9ing #bout !p#* 'ilter!.
3It
6ould, ho6e?er, be poor 'or* to di!tribute # ?er!ion o' thi! #pplic#tion u!ing # p#c9#ge !t#rting 6ith com.gigamon&e?s !ince you don@t control th#t do*#in.
-% ?er!ion 5&he
o' C -PPC$( i! included 6ith the boo9@! !ource code #?#il#ble 'ro* the boo9@! Web !ite. 5r you c#n do6nlo#d it 'ro* WeitA@! !ite #t http://www.weit*.de/cl-ppcre/. *#in re#!on to u!e PRINT-UNREADABLE-OB4ECT i! th#t it t#9e! c#re o' !ign#ling the #ppropri#te error i' !o*eone trie! to print your ob<ect re#d#bly, !uch #! 6ith the 7, FORMAT directi?e.
0PRINT-UNREADABLE-OB4ECT
#l!o !ign#l! #n error i' it@! u!ed 6hen the printer control ?#ri#ble *PRINT-READABLY* i! true. &hu!, # PRINT-OB4ECT *ethod con!i!ting !olely o' # PRINTUNREADABLE-OB4ECT 'or* 6ill correctly i*ple*ent the PRINT-OB4ECT contr#ct 6ith reg#rd to *PRINT-READABLY*.
2I'
you decide l#ter th#t you do need to h#?e di''erent ?er!ion! o' increment-(eat're 'or di''erent cl#!!e!, you c#n rede'ine increment-co'nt #! # generic 'unction #nd thi! 'unction #! # *ethod !peci#liAed on word-(eat're.
,&echnic#lly,
the 9ey in e#ch cl#u!e o' # CASE or ECASE i! interpreted #! # list designator, #n ob<ect th#t de!ign#te! # li!t o' ob<ect!. % !ingle nonli!t ob<ect, tre#ted #! # li!t de!ign#tor, de!ign#te! # li!t cont#ining <u!t th#t one ob<ect, 6hile # li!t de!ign#te! it!el'. &hu!, e#ch cl#u!e c#n h#?e *ultiple 9ey!G CASE #nd ECASE 6ill !elect the cl#u!e 6ho!e li!t o' 9ey! cont#in! the ?#lue o' the 9ey 'or*. /or e.#*ple, i' you 6#nted to *#9e good # !ynony* 'or ham #nd bad # !ynony* 'or spam, you could 6rite increment-co'nt li9e thi!:
1de('n#increment-co'nt#1(eat're#t?pe3 ##1ecase#t?pe ####11ham#good3#1inc(#1ham-co'nt#(eat're333 ####11spam#bad3#1inc(#1spam-co'nt#(eat're33333
)
Spe#9ing o' *#the*#tic#l nu#nce!, h#rd-core !t#ti!tici#n! *#y be o''ended by the !o*eti*e! loo!e u!e o' the 6ord probabilit0 in thi! ch#pter. >o6e?er, !ince e?en the pro!, 6ho #re di?ided bet6een the 7#ye!i#n! #nd the 'reFuenti!t!, c#n@t #gree on 6h#t # prob#bility i!, I@* not going to 6orry #bout it. &hi! i! # boo9 #bout progr#**ing, not !t#ti!tic!.
10$obin!on@!
#rticle! th#t directly in'or*ed thi! ch#pter #re H% St#ti!tic#l %ppro#ch to the Sp#* Proble*H Bpubli!hed in the Linu3 Journal #nd #?#il#ble #t http://www.lin')jo'rnal.com/# article.php?sid=646Q #nd in # !horter 'or* on $obin!on@! blog #t http://radio.weblogs.com/# 0 04"4/stories/! !/ 9/06/spam<etection.htmlC #nd HWhy Chi" 3oti?#tion! 'or the 8!e o' /i!her@! In?er!e Chi-SFu#re Procedure in Sp#* Cl#!!i'ic#tionH B#?#il#ble #t http://gar?rob.blogs.com/#wh?chi93.pd(C. %nother #rticle th#t *#y be u!e'ul i! H>#ndling $edund#ncy in (*#il &o9en Prob#bilitie!H B#?#il#ble #t http://gar?rob.blogs.com//handlingto&enred'ndanc?94.pd(C. &he #rchi?ed *#iling li!t! o' the Sp#*7#ye! pro<ect Bhttp://spamba?es.so'rce(orge.net/C #l!o cont#in # lot o' u!e'ul in'or*#tion #bout di''erent #lgorith*! #nd #ppro#che! to te!ting !p#* 'ilter!.
11&echniFue!
th#t co*bine nonindependent prob#bilitie! #! though they 6ere, in '#ct, independent, #re c#lled naive #a0esian. =r#h#*@! origin#l propo!#l 6#! e!!enti#lly # n#i?e 7#ye!i#n cl#!!i'ier 6ith !o*e He*piric#lly deri?edH con!t#nt '#ctor! thro6n in.
12Se?er#l 13I'
!p#* corpor# including the Sp#*%!!#!!in corpu! #re lin9ed to 'ro* http://ne)p.cs.pd).ed'/7psam/cgi-bin/view/T,I%/$orp's,ets. you 6#nted to conduct # te!t 6ithout di!turbing the e.i!ting d#t#b#!e, you could bind U(eat'redatabaseU, Utotal-spamsU, #nd Utotal-hamsU 6ith # LET, but then you@d h#?e no 6#y o' loo9ing #t the d#t#b#!e #'ter the '#ct--unle!! you returned the ?#lue! you u!ed 6ithin the 'unction.
1-&hi!
#lgorith* i! n#*ed 'or the !#*e /i!her 6ho in?ented the *ethod u!ed 'or co*bining prob#bilitie! #nd 'or /r#n9 4#te!, hi! co#uthor o' the boo9 -tatistical Tables for #iological< !gricultural and Medical *esearch B5li?er ] 7oyd, 1)3,C in 6hich, #ccording to Lnuth, they pro?ided the 'ir!t publi!hed de!cription o' the #lgorith*.
Binary Fi%es
%t # !u''iciently lo6 le?el o' #b!tr#ction, #ll 'ile! #re Hbin#ryH in the !en!e th#t they <u!t cont#in #
bunch o' nu*ber! encoded in bin#ry 'or*. >o6e?er, it@! cu!to*#ry to di!tingui!h bet6een te3t files, 6here #ll the nu*ber! c#n be interpreted #! ch#r#cter! repre!enting hu*#n-re#d#ble te.t, #nd binar0 files, 6hich cont#in d#t# th#t, i' interpreted #! ch#r#cter!, yield! nonprint#ble ch#r#cter!.1 7in#ry 'ile 'or*#t! #re u!u#lly de!igned to be both co*p#ct #nd e''icient to p#r!e--th#t@! their *#in #d?#nt#ge o?er te.t-b#!ed 'or*#t!. &o *eet both tho!e criteri#, they@re u!u#lly co*po!ed o' on-di!9 !tructure! th#t #re e#!ily *#pped to d#t# !tructure! th#t # progr#* *ight u!e to repre!ent the !#*e d#t# in *e*ory.2 &he libr#ry 6ill gi?e you #n e#!y 6#y to de'ine the *#pping bet6een the on-di!9 !tructure! de'ined by # bin#ry 'ile 'or*#t #nd in-*e*ory i!p ob<ect!. 8!ing the libr#ry, it !hould be e#!y to 6rite # progr#* th#t c#n re#d # bin#ry 'ile, tr#n!l#ting it into i!p ob<ect! th#t you c#n *#nipul#te, #nd then 6rite b#c9 out to #nother properly 'or*#tted bin#ry 'ile.
>o6e?er, Co**on i!p pro?ide! # *ore con?enient 6#y to per'or* thi! 9ind o' bit t6iddling. &he 'unction LDB, 6ho!e n#*e !t#nd! 'or lo#d byte, c#n be u!ed to e.tr#ct #nd !et B6ith SETFC #ny nu*ber o' contiguou! bit! 'ro* #n integer.- &he nu*ber o' bit! #nd their po!ition 6ithin the integer i! !peci'ied 6ith # b0te specifier cre#ted 6ith the BYTE 'unction. BYTE t#9e! t6o #rgu*ent!, the nu*ber o' bit! to e.tr#ct Bor !etC #nd the po!ition o' the right*o!t bit 6here the le#!t !igni'ic#nt bit i! #t po!ition Aero. LDB t#9e! # byte !peci'ier #nd the integer 'ro* 6hich to e.tr#ct the bit! #nd return! the po!iti?e integer repre!ented by the e.tr#cted bit!. &hu!, you c#n e.tr#ct the le#!t !igni'ic#nt octet o' #n integer li9e thi!:
1ldb#1b?te#R# 3#N)abcd3#==/#! "#S#! "#is#N)cd
&o get the ne.t octet, you@d u!e # byte !peci'ier o' 1b?te#R#R3 li9e thi!:
1ldb#1b?te#R#R3#N)abcd3#==/#0Q0#S#0Q0#is#N)ab
4ou c#n u!e LDB 6ith SETF to !et the !peci'ied bit! o' #n integer !tored in # SETF#ble pl#ce.
$L-+,-./#1de(var#Un'mU# 3 U8+%U $L-+,-./#1set(#1ldb#1b?te#R# 3#Un'mU3#0!R3 0!R $L-+,-./#Un'mU 0!R $L-+,-./#1set(#1ldb#1b?te#R#R3#Un'mU3#!""3 !"" $L-+,-./#Un'mU 6"4 R
&o 6rite # nu*ber out #! # 10-bit integer, you need to e.tr#ct the indi?idu#l ,-bit byte! #nd 6rite the* one #t # ti*e. &o e.tr#ct the indi?idu#l byte!, you <u!t need to u!e LDB 6ith the !#*e byte !peci'ier!.
1de('n#write-'!#1o't#val'e3 ##1write-b?te#1ldb#1b?te#R#R3#val'e3#o't3 ##1write-b?te#1ldb#1b?te#R# 3#val'e3#o't33
5' cour!e, you c#n #l!o encode integer! in *#ny other 6#y!--6ith di''erent nu*ber! o' byte!, 6ith di''erent endi#nne!!, #nd in !igned #nd un!igned 'or*#t.
de!igned 'or u!e 6ith the 8nicode ch#r#cter code, u!e! # !ingle octet to encode the ?#lue! 0-122 6hile u!ing up to 'our octet! to encode ?#lue! up to 1,11-,111.0 Since the code point! 'ro* 0-122 *#p to the !#*e ch#r#cter! in 8nicode #! they do in %SCII, # 8&/-, encoding o' te.t con!i!ting only o' ch#r#cter! #l!o in %SCII i! the !#*e #! the %SCII encoding. 5n the other h#nd, te.t! con!i!ting *o!tly o' ch#r#cter! reFuiring 'our byte! in 8&/-, could be *ore co*p#ctly encoded in # !tr#ight double-byte encoding. Co**on i!p pro?ide! t6o 'unction! 'or tr#n!l#ting bet6een nu*eric ch#r#cter code! #nd ch#r#cter ob<ect!: CODE-CHAR, 6hich t#9e! #n nu*eric code #nd return! #! # ch#r#cter, #nd CHAR-CODE, 6hich t#9e! # ch#r#cter #nd return! it! nu*eric code. &he l#ngu#ge !t#nd#rd doe!n@t !peci'y 6h#t ch#r#cter encoding #n i*ple*ent#tion *u!t u!e, !o there@! no gu#r#ntee you c#n repre!ent e?ery ch#r#cter th#t c#n po!!ibly be encoded in # gi?en 'ile 'or*#t #! # i!p ch#r#cter. >o6e?er, #l*o!t #ll conte*por#ry Co**on i!p i*ple*ent#tion! u!e %SCII, IS5-,,5)-1, or 8nicode #! their n#ti?e ch#r#cter code. 7ec#u!e 8nicode i! # !uper!et o'IS5-,,5)-1, 6hich i! in turn # !uper!et o' %SCII, i' you@re u!ing # 8nicode i!p, CODE-CHAR #nd CHAR-CODE c#n be u!ed directly 'or tr#n!l#ting #ny o' tho!e three ch#r#cter code!.2 In #ddition to !peci'ying # ch#r#cter encoding, # !tring encoding *u!t #l!o !peci'y ho6 to encode the length o' the !tring. &hree techniFue! #re typic#lly u!ed in bin#ry 'ile 'or*#t!. &he !i*ple!t i! to not encode it but to let it be i*plicit in the po!ition o' the !tring in !o*e l#rger !tructure: # p#rticul#r ele*ent o' # 'ile *#y #l6#y! be # !tring o' # cert#in length, or # !tring *#y be the l#!t ele*ent o' # ?#ri#ble-length d#t# !tructure 6ho!e o?er#ll !iAe deter*ine! ho6 *#ny byte! #re le't to re#d #! !tring d#t#. 7oth the!e techniFue! #re u!ed in I+3 t#g!, #! you@ll !ee in the ne.t ch#pter. &he other t6o techniFue! c#n be u!ed to encode ?#ri#ble-length !tring! 6ithout relying on conte.t. 5ne i! to encode the length o' the !tring 'ollo6ed by the ch#r#cter d#t#--the p#r!er re#d! #n integer ?#lue Bin !o*e !peci'ied integer 'or*#tC #nd then re#d! th#t nu*ber o' ch#r#cter!. %nother i! to 6rite the ch#r#cter d#t# 'ollo6ed by # deli*iter th#t c#n@t #ppe#r in the !tring !uch #! # null ch#r#cter. &he di''erent repre!ent#tion! h#?e di''erent #d?#nt#ge! #nd di!#d?#nt#ge!, but 6hen you@re de#ling 6ith #lre#dy !peci'ied bin#ry 'or*#t!, you 6on@t h#?e #ny control o?er 6hich encoding i! u!ed. >o6e?er, none o' the encoding! i! p#rticul#rly *ore di''icult to re#d #nd 6rite th#n #ny other. >ere, #! #n e.#*ple, i! # 'unction th#t re#d! # null-ter*in#ted %SCII !tring, #!!u*ing your i!p i*ple*ent#tion u!e! %SCII or one o' it! !uper!et! !uch #! IS5-,,5)-1 or 'ull 8nicode #! it! n#ti?e ch#r#cter encoding:
1de(constant#2n'll2#1code-char# 33 1de('n#read-n'll-terminated-ascii#1in3 ##1with-o'tp't-to-string#1s3 ####1loop#(or#char#=#1code-char#1read-b?te#in33 ##########'ntil#1char=#char#2n'll23#do#1write-char#char#s3333
&he WITH-OUTPUT-TO-STRING *#cro, 6hich I *entioned in Ch#pter 1-, i! #n e#!y 6#y to build up # !tring 6hen you don@t 9no6 ho6 long it@ll be. It cre#te! # STRING-STREAM #nd bind! it to the ?#ri#ble n#*e !peci'ied, s in thi! c#!e. %ll ch#r#cter! 6ritten to the !tre#* #re collected into # !tring, 6hich i! then returned #! the ?#lue o' the WITH-OUTPUT-TO-STRING 'or*. &o 6rite # !tring b#c9 out, you <u!t need to tr#n!l#te the ch#r#cter! b#c9 to nu*eric ?#lue! th#t c#n be 6ritten 6ith WRITE-BYTE #nd then 6rite the null ter*in#tor #'ter the !tring content!.
1de('n#write-n'll-terminated-ascii#1string#o't3 ##1loop#(or#char#across#string ########do#1write-b?te#1char-code#char3#o't33
##1write-b?te#1char-code#2n'll23#o't33
%! the!e e.#*ple! !ho6, the *#in intellectu#l ch#llenge--!uch #! it i!--o' re#ding #nd 6riting pri*iti?e ele*ent! o' bin#ry 'ile! i! under!t#nding ho6 e.#ctly to interpret the byte! th#t #ppe#r in # 'ile #nd to *#p the* to i!p d#t# type!. I' # bin#ry 'ile 'or*#t i! 6ell !peci'ied, thi! !hould be # !tr#ight'or6#rd propo!ition. %ctu#lly 6riting 'unction! to re#d #nd 6rite # p#rticul#r encoding i!, #! they !#y, # !i*ple *#tter o' progr#**ing. :o6 you c#n turn to the i!!ue o' re#ding #nd 6riting *ore co*ple. on-di!9 !tructure! #nd ho6 to *#p the* to i!p ob<ect!.
#o$posite /tructures
Since bin#ry 'or*#t! #re u!u#lly u!ed to repre!ent d#t# in # 6#y th#t *#9e! it e#!y to *#p to in*e*ory d#t# !tructure!, it !hould co*e #! no !urpri!e th#t co*po!ite on-di!9 !tructure! #re u!u#lly de'ined in 6#y! !i*il#r to the 6#y progr#**ing l#ngu#ge! de'ine in-*e*ory !tructure!. 8!u#lly # co*po!ite on-di!9 !tructure 6ill con!i!t o' # nu*ber o' n#*ed p#rt!, e#ch o' 6hich i! it!el' either # pri*iti?e type !uch #! # nu*ber or # !tring, #nother co*po!ite !tructure, or po!!ibly # collection o' !uch ?#lue!. /or in!t#nce, #n I+3 t#g de'ined in the 2.2 ?er!ion o' the !peci'ic#tion con!i!t! o' # he#der *#de up o' # three-ch#r#cter IS5-,,5)-1 !tring, 6hich i! #l6#y! HI+3HG t6o one-byte un!igned integer! th#t !peci'y the *#<or ?er!ion #nd re?i!ion o' the !peci'ic#tionG eight bit! 6orth o' boole#n 'l#g!G #nd 'our byte! th#t encode the !iAe o' the t#g in #n encoding p#rticul#r to the I+3 !peci'ic#tion. /ollo6ing the he#der i! # li!t o' frames, e#ch o' 6hich h#! it! o6n intern#l !tructure. %'ter the 'r#*e! #re #! *#ny null byte! #! #re nece!!#ry to p#d the t#g out to the !iAe !peci'ied in the he#der. I' you loo9 #t the 6orld through the len! o' ob<ect orient#tion, co*po!ite !tructure! loo9 # lot li9e cl#!!e!. /or in!t#nce, you could 6rite # cl#!! to repre!ent #n I+3 t#g.
1de(class#id3-tag#13 ##11identi(ier####:initarg#:identi(ier####:accessor#identi(ier3 ###1major-version#:initarg#:major-version#:accessor#major-version3 ###1revision######:initarg#:revision######:accessor#revision3 ###1(lags#########:initarg#:(lags#########:accessor#(lags3 ###1si*e##########:initarg#:si*e##########:accessor#si*e3 ###1(rames########:initarg#:(rames########:accessor#(rames333
%n in!t#nce o' thi! cl#!! 6ould *#9e # per'ect repo!itory to hold the d#t# needed to repre!ent #n I+3 t#g. 4ou could then 6rite 'unction! to re#d #nd 6rite in!t#nce! o' thi! cl#!!. /or e.#*ple, #!!u*ing the e.i!tence o' cert#in other 'unction! 'or re#ding the #ppropri#te pri*iti?e d#t# type!, # read-id3tag 'unction *ight loo9 li9e thi!:
1de('n#read-id3-tag#1in3 ##1let#11tag#1ma&e-instance#Cid3-tag333 ####1with-slots#1identi(ier#major-version#revision#(lags#si*e#(rames3#tag ######1set(#identi(ier####1read-iso-RR"9-0-string#in#:length#333 ######1set(#major-version#1read-'0#in33 ######1set(#revision######1read-'0#in33 ######1set(#(lags#########1read-'0#in33 ######1set(#si*e##########1read-id3-encoded-si*e#in33 ######1set(#(rames########1read-id3-(rames#in#:tag-si*e#si*e333 ####tag33
&he write-id3-tag 'unction 6ould be !tructured !i*il#rly--you@d u!e the #ppropri#te write-U 'unction! to 6rite out the ?#lue! !tored in the !lot! o' the id3-tag ob<ect. It@! not h#rd to !ee ho6 you could 6rite the #ppropri#te cl#!!e! to repre!ent #ll the co*po!ite d#t# !tructure! in # !peci'ic#tion #long 6ith read-(oo #nd write-(oo 'unction! 'or e#ch cl#!! #nd 'or nece!!#ry pri*iti?e type!. 7ut it@! #l!o e#!y to tell th#t #ll the re#ding #nd 6riting 'unction! #re going to be pretty !i*il#r, di''ering only in the !peci'ic! o' 6h#t type! they re#d #nd the n#*e! o' the !lot! they !tore the* in. It@! p#rticul#rly ir9!o*e 6hen you con!ider th#t in the I+3 !peci'ic#tion it t#9e! #bout 'our line! o' te.t to !peci'y the !tructure o' #n I+3 t#g, 6hile you@?e #lre#dy 6ritten eighteen line! o' code #nd h#?en@t e?en 6ritten write-id3-tag yet. Wh#t you@d re#lly li9e i! # 6#y to de!cribe the !tructure o' !o*ething li9e #n I+3 t#g in # 'or* th#t@! #! co*pre!!ed #! the !peci'ic#tion@! p!eudocode yet th#t c#n #l!o be e.p#nded into code th#t de'ine! the id3-tag cl#!! and the 'unction! th#t tr#n!l#te bet6een byte! on di!9 #nd in!t#nce! o' the cl#!!. Sound! li9e # <ob 'or # *#cro.
In the not#tion o' the !peci'ic#tion, thi! *e#n! the H'ile identi'ierH !lot o' #n I+3 t#g i! the !tring HI+3H in IS5-,,5)-1 encoding. &he ?er!ion con!i!t! o' t6o byte!, the 'ir!t o' 6hich--'or thi! ?er!ion o' the !peci'ic#tion--h#! the ?#lue 2 #nd the !econd o' 6hich--#g#in 'or thi! ?er!ion o' the !peci'ic#tion--i! 0. &he 'l#g! !lot i! eight bit!, o' 6hich #ll but the 'ir!t t6o #re 0, #nd the !iAe con!i!t! o' 'our byte!, e#ch o' 6hich h#! # 0 in the *o!t !igni'ic#nt bit. So*e in'or*#tion i!n@t c#ptured by thi! p!eudocode. /or in!t#nce, e.#ctly ho6 the 'our byte! th#t encode the !iAe #re to be interpreted i! de!cribed in # 'e6 line! o' pro!e. i9e6i!e, the !pec de!cribe! in pro!e ho6 the 'r#*e #nd !ub!eFuent p#dding i! !tored #'ter thi! he#der. 7ut *o!t o' 6h#t you need to 9no6 to be #ble to 6rite code to re#d #nd 6rite #n I+3 t#g i! !peci'ied by thi! p!eudocode. &hu!, you ought to be #ble to 6rite #n !-e.pre!!ion ?er!ion o' thi! p!eudocode #nd h#?e it e.p#nded into the cl#!! #nd 'unction de'inition! you@d other6i!e h#?e to 6rite by h#nd--!o*ething, perh#p!, li9e thi!:
1de(ine-binar?-class#id3-tag ##11(ile-identi(ier#1iso-RR"9-0-string#:length#333 ###1major-version###'03 ###1revision########'03 ###1(lags###########'03 ###1si*e############id3-tag-si*e3 ###1(rames##########1id3-(rames#:tag-si*e#si*e3333
&he b#!ic ide# i! th#t thi! 'or* de'ine! # cl#!! id3-tag !i*il#r to the 6#y you could 6ith DEFCLASS, but in!te#d o' !peci'ying thing! !uch #! :initarg #nd :accessors, e#ch !lot !peci'ic#tion con!i!t! o' the n#*e o' the !lot--(ile-identi(ier, major-version, #nd !o on--
#nd in'or*#tion #bout ho6 th#t !lot i! repre!ented on di!9. Since thi! i! <u!t # bit o' '#nt#!iAing, you don@t h#?e to 6orry #bout e.#ctly ho6 the *#cro de(ine-binar?-class 6ill 9no6 6h#t to do 6ith e.pre!!ion! !uch #! 1iso-RR"9-0-string#:length#33, '0, id3-tag-si*e, #nd 1id3-(rames#:tag-si*e#si*e3G #! long #! e#ch e.pre!!ion cont#in! the in'or*#tion nece!!#ry to 9no6 ho6 to re#d #nd 6rite # p#rticul#r d#t# encoding, you !hould be o9#y.
&he $;%.J9JI%;8M-H,.%I$.;-+F9L9F9-, p#c9#ge cont#in! the with-gens?ms #nd onceonl? *#cro! 'ro* Ch#pter ,. Since you #lre#dy h#?e # h#nd6ritten ?er!ion o' the code you 6#nt to gener#te, it !houldn@t be too h#rd to 6rite !uch # *#cro. Du!t t#9e it in !*#ll piece!, !t#rting 6ith # ?er!ion o' de(ine-binar?class th#t gener#te! <u!t the DEFCLASS 'or*. I' you loo9 b#c9 #t the de(ine-binar?-class 'or*, you@ll !ee th#t it t#9e! t6o #rgu*ent!, the n#*e id3-tag #nd # li!t o' !lot !peci'ier!, e#ch o' 6hich i! it!el' # t6o-ite* li!t. /ro* tho!e piece! you need to build the #ppropri#te DEFCLASS 'or*. Cle#rly, the bigge!t di''erence bet6een the de(ine-binar?-class 'or* #nd # proper DEFCLASS 'or* i! in the !lot !peci'ier!. % !ingle !lot !peci'ier 'ro* de(ine-binar?-class loo9! !o*ething li9e thi!:
1major-version#'03
7ut th#t@! not # leg#l !lot !peci'ier 'or # DEFCLASS. In!te#d, you need !o*ething li9e thi!:
1major-version#:initarg#:major-version#:accessor#major-version3
(#!y enough. /ir!t de'ine # !i*ple 'unction to tr#n!l#te # !y*bol to the corre!ponding 9ey6ord !y*bol.
1de('n#as-&e?word#1s?m3#1intern#1string#s?m3#:&e?word33
:o6 de'ine # 'unction th#t t#9e! # de(ine-binar?-class !lot !peci'ier #nd return! # DEFCLASS !lot !peci'ier.
1de('n#slot-/de(class-slot#1spec3 ##1let#11name#1(irst#spec333 ####B15name#:initarg#51as-&e?word#name3#:accessor#5name333
4ou c#n te!t thi! 'unction #t the $(P #'ter !6itching to your ne6 p#c9#ge 6ith # c#ll to INPAC+AGE.
L98I.H-<IFI/#1slot-/de(class-slot#C1major-version#'033 1%I_;.-K-.,9;8#:989FI.J#:%I_;.-K-.,9;8#:I$$-,,;.#%I_;.-K-.,9;83
&hi! i! !i*ple te*pl#te-!tyle *#cro--de(ine-binar?-class gener#te! # DEFCLASS 'or* by interpol#ting the n#*e o' the cl#!! #nd # li!t o' !lot !peci'ier! con!tructed by #pplying slot/de(class-slot to e#ch ele*ent o' the li!t o' !lot! !peci'ier! 'ro* the de(ine-binar?class 'or*. &o !ee e.#ctly 6h#t code thi! *#cro gener#te!, you c#n e?#lu#te thi! e.pre!!ion #t the $(P .
1macroe)pand-0#C1de(ine-binar?-class#id3-tag ##11identi(ier######1iso-RR"9-0-string#:length#333 ###1major-version###'03 ###1revision########'03 ###1(lags###########'03 ###1si*e############id3-tag-si*e3 ###1(rames##########1id3-(rames#:tag-si*e#si*e33333
&he re!ult, !lightly re'or*#tted here 'or better re#d#bility, !hould loo9 '#*ili#r !ince it@! e.#ctly the cl#!! de'inition you 6rote by h#nd e#rlier:
1de(class#id3-tag#13 ##11identi(ier######:initarg#:identi(ier####:accessor#identi(ier3 ###1major-version###:initarg#:major-version#:accessor#major-version3 ###1revision########:initarg#:revision######:accessor#revision3 ###1(lags###########:initarg#:(lags#########:accessor#(lags3 ###1si*e############:initarg#:si*e##########:accessor#si*e3 ###1(rames##########:initarg#:(rames########:accessor#(rames333
*#cro c#n 'igure out the n#*e o' the 'unction to c#ll b#!ed on the n#*e o' the type in the !lot !peci'ier. >o6e?er, thi! 6ould reFuire de(ine-binar?-class to gener#te the n#*e read-id3-tag, 6hich i! po!!ible but # b#d ide#. 3#cro! th#t cre#te glob#l de'inition! !hould gener#lly u!e only n#*e! p#!!ed to the* by their c#ller!G *#cro! th#t gener#te n#*e! under the co?er! c#n c#u!e h#rd-topredict--#nd h#rd-to-debug--n#*e con'lict! 6hen the gener#ted n#*e! h#ppen to be the !#*e #! n#*e! u!ed el!e6here., 4ou c#n #?oid both the!e incon?enience! by noticing th#t #ll the 'unction! th#t re#d # p#rticul#r type o' ?#lue h#?e the !#*e 'und#*ent#l purpo!e, to re#d # ?#lue o' # !peci'ic type 'ro* # !tre#*. Spe#9ing colloFui#lly, you *ight !#y they@re #ll in!t#nce! o' # !ingle generic oper#tion. %nd the colloFui#l u!e o' the 6ord generic !hould le#d you directly to the !olution to your proble*: in!te#d o' de'ining # bunch o' independent 'unction!, #ll 6ith di''erent n#*e!, you c#n de'ine # !ingle generic 'unction, readval'e, 6ith *ethod! !peci#liAed to re#d di''erent type! o' ?#lue!. &h#t i!, in!te#d o' de'ining 'unction! read-iso-RR"9-0-string #nd read-'0, you c#n de'ine read-val'e #! # generic 'unction t#9ing t6o reFuired #rgu*ent!, # type #nd # !tre#*, #nd po!!ibly !o*e 9ey6ord #rgu*ent!.
1de(generic#read-val'e#1t?pe#stream#>&e?3 ##1:doc'mentation#4.ead#a#val'e#o(#the#given#t?pe#(rom#the#stream.433
7y !peci'ying &)'* 6ithout #ny #ctu#l 9ey6ord p#r#*eter!, you #llo6 di''erent *ethod! to de'ine their o6n &)'* p#r#*eter! 6ithout reFuiring the* to do !o. &hi! doe! *e#n e?ery *ethod !peci#liAed on read-val'e 6ill h#?e to include either &)'* or #n &&'(! p#r#*eter in it! p#r#*eter li!t to be co*p#tible 6ith the generic 'unction. &hen you@ll de'ine *ethod! th#t u!e EQL !peci#liAer! to !peci#liAe the type #rgu*ent on the n#*e o' the type you 6#nt to re#d.
1de(method#read-val'e#11t?pe#1e@l#Ciso-RR"9-0-string33#in#>&e?#length3#...3 1de(method#read-val'e#11t?pe#1e@l#C'033#in#>&e?3#...3
&hen you c#n *#9e de(ine-binar?-class gener#te # read-val'e *ethod !peci#liAed on the type n#*e id3-tag, #nd th#t *ethod c#n be i*ple*ented in ter*! o' c#ll! to read-val'e 6ith the #ppropri#te !lot type! #! the 'ir!t #rgu*ent. &he code you 6#nt to gener#te i! going to loo9 li9e thi!:
1de(method#read-val'e#11t?pe#1e@l#Cid3-tag33#in#>&e?3 ##1let#11object#1ma&e-instance#Cid3-tag333 ####1with-slots#1identi(ier#major-version#revision#(lags#si*e#(rames3#object ######1set(#identi(ier####1read-val'e#Ciso-RR"9-0-string#in#:length#333 ######1set(#major-version#1read-val'e#C'0#in33 ######1set(#revision######1read-val'e#C'0#in33 ######1set(#(lags#########1read-val'e#C'0#in33 ######1set(#si*e##########1read-val'e#Cid3-encoded-si*e#in33 ######1set(#(rames########1read-val'e#Cid3-(rames#in#:tag-si*e#si*e333 ####object33
So, <u!t #! you needed # 'unction to tr#n!l#te # de(ine-binar?-class !lot !peci'ier to # DEFCLASS !lot !peci'ier in order to gener#te the DEFCLASS 'or*, no6 you need # 'unction th#t t#9e! # de(ine-binar?-class !lot !peci'ier #nd gener#te! the #ppropri#te SETF 'or*, th#t i!, !o*ething th#t t#9e! thi!:
1identi(ier#1iso-RR"9-0-string#:length#333
>o6e?er, there@! # di''erence bet6een thi! code #nd the DEFCLASS !lot !peci'ier: it include! # re'erence to # ?#ri#ble in--the *ethod p#r#*eter 'ro* the read-val'e *ethod--th#t 6#!n@t deri?ed 'ro* the !lot !peci'ier. It doe!n@t h#?e to be c#lled in, but 6h#te?er n#*e you u!e h#! to be the !#*e #! the one u!ed in the *ethod@! p#r#*eter li!t #nd in the other c#ll! to read-val'e. /or no6 you c#n dodge the i!!ue o' 6here th#t n#*e co*e! 'ro* by de'ining slot-/read-val'e to t#9e # !econd #rgu*ent o' the n#*e o' the !tre#* ?#ri#ble.
1de('n#slot-/read-val'e#1spec#stream3 ##1destr'ct'ring-bind#1name#1t?pe#>rest#args33#1normali*e-slot-spec#spec3 ####B1set(#5name#1read-val'e#C5t?pe#5stream#5Pargs3333
&he 'unction normali*e-slot-spec nor*#liAe! the !econd ele*ent o' the !lot !peci'ier, con?erting # !y*bol li9e '0 to the li!t 1'03 !o the DESTRUCTURING-BIND c#n p#r!e it. It loo9! li9e thi!:
1de('n#normali*e-slot-spec#1spec3 ##1list#1(irst#spec3#1m&list#1second#spec3333 1de('n#m&list#1)3#1i(#1listp#)3#)#1list#)333
4ou c#n te!t slot-/read-val'e 6ith e#ch type o' !lot !peci'ier.
L98I.H-<IFI/#1slot-/read-val'e#C1major-version#'03#Cstream3 1,-FE#%I_;.-K-.,9;8#1.-I<-KIL+-#C+0#,F.-I%33 L98I.H-<IFI/#1slot-/read-val'e#C1identi(ier#1iso-RR"9-0-string#:length#333# Cstream3 1,-FE#9<-8F9E9-.#1.-I<-KIL+-#C9,;-RR"9-0-,F.98J#,F.-I%#:L-8JF:#333
With the!e 'unction! you@re re#dy to #dd read-val'e to de(ine-binar?-class. I' you t#9e the h#nd6ritten read-val'e *ethod #nd !trip out #nything th#t@! tied to # p#rticul#r cl#!!, you@re le't 6ith thi! !9eleton:
1de(method#read-val'e#11t?pe#1e@l#...33#stream#>&e?3 ##1let#11object#1ma&e-instance#...333 ####1with-slots#1...3#object ######... ####object333
%ll you need to do i! #dd thi! !9eleton to the de(ine-binar?-class te*pl#te, repl#cing ellip!e! 6ith code th#t 'ill! in the !9eleton 6ith the #ppropri#te n#*e! #nd code. 4ou@ll #l!o 6#nt to repl#ce the ?#ri#ble! t?pe, stream, #nd object 6ith gen!y*ed n#*e! to #?oid potenti#l con'lict! 6ith !lot n#*e!,) 6hich you c#n do 6ith the with-gens?ms *#cro 'ro* Ch#pter ,. %l!o, bec#u!e # *#cro *u!t e.p#nd into # !ingle 'or*, you need to 6r#p !o*e 'or* #round the DEFCLASS #nd DEFMETHOD. PROGN i! the cu!to*#ry 'or* to u!e 'or *#cro! th#t e.p#nd into *ultiple de'inition! bec#u!e o' the !peci#l tre#t*ent it get! 'ro* the 'ile co*piler 6hen #ppe#ring #t the top le?el o' # 'ile, #! I di!cu!!ed in Ch#pter 20. So, you c#n ch#nge de(ine-binar?-class #! 'ollo6!:
1de(macro#de(ine-binar?-class#1name#slots3 ##1with-gens?ms#1t?pevar#objectvar#streamvar3
&hen you de'ine # helper 'unction th#t tr#n!l#te! # de(ine-binar?-class !lot !peci'ier into code th#t 6rite! out the !lot u!ing write-val'e. %! 6ith the slot-/read-val'e 'unction, thi! helper 'unction need! to t#9e the n#*e o' the !tre#* ?#ri#ble #! #n #rgu*ent.
1de('n#slot-/write-val'e#1spec#stream3 ##1destr'ct'ring-bind#1name#1t?pe#>rest#args33#1normali*e-slot-spec#spec3 ####B1write-val'e#C5t?pe#5stream#5name#5Pargs333
deter*ine 6h#t 9ind o' 'r#*e you@re loo9ing #t #nd thu! ho6 to p#r!e the body o' the 'r#*e. &he current de(ine-binar?-class *#cro h#! no 6#y to h#ndle thi! 9ind o' re#ding--you could u!e de(ine-binar?-class to de'ine # cl#!! to repre!ent e#ch 9ind o' 'r#*e, but you@d h#?e no 6#y to 9no6 6h#t type o' 'r#*e to re#d 6ithout re#ding #t le#!t the identi'ier. %nd i' other code re#d! the identi'ier in order to deter*ine 6h#t type to p#!! to read-val'e, then th#t 6ill bre#9 readval'e !ince it@! e.pecting to re#d #ll the d#t# th#t *#9e! up the in!t#nce o' the cl#!! it in!t#nti#te!. 4ou c#n !ol?e thi! proble* by #dding inherit#nce to de(ine-binar?-class #nd then 6riting #nother *#cro, de(ine-tagged-binar?-class, 'or de'ining H#b!tr#ctH cl#!!e! th#t #ren@t in!t#nti#ted directly but th#t c#n be !peci#liAed on by read-val'e *ethod! th#t 9no6 ho6 to re#d enough d#t# to deter*ine 6h#t 9ind o' cl#!! to cre#te. &he 'ir!t !tep to #dding inherit#nce to de(ine-binar?-class i! to #dd # p#r#*eter to the *#cro to #ccept # li!t o' !upercl#!!e!.
1de(macro#de(ine-binar?-class#1name#1>rest#s'perclasses3#slots3#...
&hen, in the DEFCLASS te*pl#te, interpol#te th#t ?#lue in!te#d o' the e*pty li!t.
1de(class#5name#5s'perclasses ##...3
>o6e?er, there@! # bit *ore to it th#n th#t. 4ou #l!o need to ch#nge the read-val'e #nd writeval'e *ethod! !o the *ethod! gener#ted 6hen de'ining # !upercl#!! c#n be u!ed by the *ethod! gener#ted #! p#rt o' # !ubcl#!! to re#d #nd 6rite inherited !lot!. &he current 6#y read-val'e 6or9! i! p#rticul#rly proble*#tic !ince it in!t#nti#te! the ob<ect be'ore 'illing it in--ob?iou!ly, you c#n@t h#?e the *ethod re!pon!ible 'or re#ding the !upercl#!!@! 'ield! in!t#nti#te one ob<ect 6hile the !ubcl#!!@! *ethod in!t#nti#te! #nd 'ill! in # di''erent ob<ect. 4ou c#n 'i. th#t proble* by !plitting read-val'e into t6o p#rt!--one re!pon!ible 'or in!t#nti#ting the correct 9ind o' ob<ect #nd #nother re!pon!ible 'or 'illing !lot! in #n e.i!ting ob<ect. 5n the 6riting !ide it@! # bit !i*pler, but you c#n u!e the !#*e techniFue. So you@ll de'ine t6o ne6 generic 'unction!, read-object #nd write-object, th#t 6ill both t#9e #n e.i!ting ob<ect #nd # !tre#*. 3ethod! on the!e generic 'unction! 6ill be re!pon!ible 'or re#ding or 6riting the !lot! !peci'ic to the cl#!! o' the ob<ect on 6hich they@re !peci#liAed.
1de(generic#read-object#1object#stream3 ##1:method-combination#progn#:most-speci(ic-last3 ##1:doc'mentation#4Eill#in#the#slots#o(#object#(rom#stream.433 1de(generic#write-object#1object#stream3 ##1:method-combination#progn#:most-speci(ic-last3 ##1:doc'mentation#4Write#o't#the#slots#o(#object#to#the#stream.433
+e'ining the!e generic 'unction! to u!e the PROGN *ethod co*bin#tion 6ith the option :mostspeci(ic-last #llo6! you to de'ine *ethod! th#t !peci#liAe object on e#ch bin#ry cl#!! #nd h#?e the* de#l only 6ith the !lot! #ctu#lly de'ined in th#t cl#!!G the PROGN *ethod co*bin#tion 6ill co*bine #ll the #pplic#ble *ethod! !o the *ethod !peci#liAed on the le#!t !peci'ic cl#!! in the hier#rchy run! 'ir!t, re#ding or 6riting the !lot! de'ined in th#t cl#!!, then the *ethod !peci#liAed on ne.t le#!t !peci'ic !ubcl#!!, #nd !o on. %nd !ince #ll the he#?y li'ting 'or # !peci'ic cl#!! i! no6 going to be done by read-object #nd write-object, you don@t e?en need to de'ine !peci#liAed read-val'e #nd write-val'e *ethod!G you c#n de'ine de'#ult *ethod! th#t #!!u*e the type #rgu*ent i! the n#*e o' # bin#ry cl#!!.
1de(method#read-val'e#11t?pe#s?mbol3#stream#>&e?3 ##1let#11object#1ma&e-instance#t?pe333 ####1read-object#object#stream3 ####object33 1de(method#write-val'e#11t?pe#s?mbol3#stream#val'e#>&e?3 ##1assert#1t?pep#val'e#t?pe33 ##1write-object#val'e#stream33
:ote ho6 you c#n u!e MA+E-INSTANCE #! # generic ob<ect '#ctory--6hile you nor*#lly c#ll MA+EINSTANCE 6ith # Fuoted !y*bol #! the 'ir!t #rgu*ent bec#u!e you nor*#lly 9no6 e.#ctly 6h#t cl#!! you 6#nt to in!t#nti#te, you c#n u!e #ny e.pre!!ion th#t e?#lu#te! to # cl#!! n#*e !uch #!, in thi! c#!e, the t?pe p#r#*eter in the read-val'e *ethod. &he #ctu#l ch#nge! to de(ine-binar?-class to de'ine *ethod! on read-object #nd writeobject r#ther th#n read-val'e #nd write-val'e #re '#irly *inor.
1de(macro#de(ine-binar?-class#1name#s'perclasses#slots3 ##1with-gens?ms#1objectvar#streamvar3 ####B1progn #######1de(class#5name#5s'perclasses #########51mapcar#NCslot-/de(class-slot#slots33 #######1de(method#read-object#progn#115objectvar#5name3#5streamvar3 #########1with-slots#51mapcar#NC(irst#slots3#5objectvar ###########5P1mapcar#NC1lambda#1)3#1slot-/read-val'e#)#streamvar33#slots333 #######1de(method#write-object#progn#115objectvar#5name3#5streamvar3 #########1with-slots#51mapcar#NC(irst#slots3#5objectvar ###########5P1mapcar#NC1lambda#1)3#1slot-/write-val'e#)#streamvar33#slots333333
&he re'erence to si*e in the !peci'ic#tion o' data 6or9! the 6#y you@d e.pect bec#u!e the
e.pre!!ion! th#t re#d #nd 6rite the data !lot #re 6r#pped in # WITH-SLOTS th#t li!t! #ll the ob<ect@! !lot!. >o6e?er, i' you try to !plit th#t cl#!! into t6o cl#!!e! li9e thi!:
1de(ine-binar?-class#(rame#13 ##11id#1iso-RR"9-0-string#:length#333 ###1si*e#'3333 1de(ine-binar?-class#generic-(rame#1(rame3 ##11data#1raw-b?tes#:b?tes#si*e3333
you@ll get # co*pile-ti*e 6#rning 6hen you co*pile the generic-(rame de'inition #nd # runti*e error 6hen you try to u!e it bec#u!e there 6ill be no le.ic#lly #pp#rent ?#ri#ble si*e in the readobject #nd write-object *ethod! !peci#liAed on generic-(rame. Wh#t you need to do i! 9eep tr#c9 o' the !lot! de'ined by e#ch bin#ry cl#!! #nd then include inherited !lot! in the WITH-SLOTS 'or*! in the read-object #nd write-object *ethod!. &he e#!ie!t 6#y to 9eep tr#c9 o' in'or*#tion li9e thi! i! to h#ng it o'' the !y*bol th#t n#*e! the cl#!!. %! I di!cu!!ed in Ch#pter 21, e?ery !y*bol ob<ect h#! #n #!!oci#ted property li!t, 6hich c#n be #cce!!ed ?i# the 'unction! SYMBOL-PLIST #nd GET. 4ou c#n #!!oci#te #rbitr#ry 9ey;?#lue p#ir! 6ith # !y*bol by #dding the* to it! property li!t 6ith SETF o' GET. /or in!t#nce, i' the bin#ry cl#!! (oo de'ine! three !lot!--), ?, #nd *--you c#n 9eep tr#c9 o' th#t '#ct by #dding # slots 9ey to the !y*bol (oo@! property li!t 6ith the ?#lue 1)#?#*3 6ith thi! e.pre!!ion:
1set(#1get#C(oo#Cslots3#C1)#?#*33
4ou 6#nt thi! boo99eeping to h#ppen #! p#rt o' e?#lu#ting the de(ine-binar?-class o' (oo. >o6e?er, it@! not cle#r 6here to put the e.pre!!ion. I' you e?#lu#te it 6hen you co*pute the *#cro@! e.p#n!ion, it@ll get e?#lu#ted 6hen you co*pile the de(ine-binar?-class 'or* but not i' you l#ter lo#d # 'ile th#t cont#in! the re!ulting co*piled code. 5n the other h#nd, i' you include the e.pre!!ion in the e.p#n!ion, then it won(t be e?#lu#ted during co*pil#tion, 6hich *e#n! i' you co*pile # 'ile 6ith !e?er#l de(ine-binar?-class 'or*!, none o' the in'or*#tion #bout 6h#t cl#!!e! de'ine 6h#t !lot! 6ill be #?#il#ble until the 6hole 'ile i! lo#ded, 6hich i! too l#te. &hi! i! 6h#t the !peci#l oper#tor EVAL-WHEN I di!cu!!ed in Ch#pter 20 i! 'or. 7y 6r#pping # 'or* in #n EVAL-WHEN, you c#n control 6hether it@! e?#lu#ted #t co*pile ti*e, 6hen the co*piled code i! lo#ded, or both. /or c#!e! li9e thi! 6here you 6#nt to !Fuirrel #6#y !o*e in'or*#tion during the co*pil#tion o' # *#cro 'or* th#t you #l!o 6#nt to be #?#il#ble #'ter the co*piled 'or* i! lo#ded, you !hould 6r#p it in #n EVAL-WHEN li9e thi!:
1eval-when#1:compile-toplevel#:load-toplevel#:e)ec'te3 ##1set(#1get#C(oo#Cslots3#C1)#?#*333
#nd include the EVAL-WHEN in the e.p#n!ion gener#ted by the *#cro. &hu!, you c#n !#?e both the !lot! #nd the direct !upercl#!!e! o' # bin#ry cl#!! by #dding thi! 'or* to the e.p#n!ion gener#ted by de(ine-binar?-class:
1eval-when#1:compile-toplevel#:load-toplevel#:e)ec'te3 ##1set(#1get#C5name#Cslots3#C51mapcar#NC(irst#slots33 ##1set(#1get#C5name#Cs'perclasses3#C5s'perclasses33
:o6 you c#n de'ine three helper 'unction! 'or #cce!!ing thi! in'or*#tion. &he 'ir!t !i*ply return! the !lot! directly de'ined by # bin#ry cl#!!. It@! # good ide# to return # copy o' the li!t !ince you don@t 6#nt other code to *odi'y the li!t o' !lot! #'ter the bin#ry cl#!! h#! been de'ined.
1de('n#direct-slots#1name3 ##1cop?-list#1get#name#Cslots333
&he ne.t 'unction return! the !lot! inherited 'ro* other bin#ry cl#!!e!.
1de('n#inherited-slots#1name3 ##1loop#(or#s'per#in#1get#name#Cs'perclasses3 ########nconc#1direct-slots#s'per3 ########nconc#1inherited-slots#s'per333
/in#lly, you c#n de'ine # 'unction th#t return! # li!t cont#ining the n#*e! o' #ll directly de'ined #nd inherited !lot!.
1de('n#all-slots#1name3 ##1nconc#1direct-slots#name3#1inherited-slots#name333
When you@re co*puting the e.p#n!ion o' # de(ine-generic-binar?-class 'or*, you 6#nt to gener#te # WITH-SLOTS 'or* th#t cont#in! the n#*e! o' #ll the !lot! de'ined in the ne6 cl#!! #nd #ll it! !upercl#!!e!. >o6e?er, you c#n@t u!e all-slots 6hile you@re gener#ting the e.p#n!ion !ince the in'or*#tion 6on@t be #?#il#ble until #'ter the e.p#n!ion i! co*piled. In!te#d, you !hould u!e the 'ollo6ing 'unction, 6hich t#9e! the li!t o' !lot !peci'ier! #nd !upercl#!!e! p#!!ed to de(inegeneric-binar?-class #nd u!e! the* to co*pute the li!t o' #ll the ne6 cl#!!@! !lot!:
1de('n#new-class-all-slots#1slots#s'perclasses3 ##1nconc#1mapcan#NCall-slots#s'perclasses3#1mapcar#NC(irst#slots333
With the!e 'unction! de'ined, you c#n ch#nge de(ine-binar?-class to !tore the in'or*#tion #bout the cl#!! currently being de'ined #nd to u!e the #lre#dy !tored in'or*#tion #bout the !upercl#!!e!@ !lot! to gener#te the WITH-SLOTS 'or*! you 6#nt li9e thi!:
1de(macro#de(ine-binar?-class#1name#1>rest#s'perclasses3#slots3 ##1with-gens?ms#1objectvar#streamvar3 ####B1progn #######1eval-when#1:compile-toplevel#:load-toplevel#:e)ec'te3 #########1set(#1get#C5name#Cslots3#C51mapcar#NC(irst#slots33 #########1set(#1get#C5name#Cs'perclasses3#C5s'perclasses33 #######1de(class#5name#5s'perclasses #########51mapcar#NCslot-/de(class-slot#slots33 #######1de(method#read-object#progn#115objectvar#5name3#5streamvar3 #########1with-slots#51new-class-all-slots#slots#s'perclasses3#5objectvar ###########5P1mapcar#NC1lambda#1)3#1slot-/read-val'e#)#streamvar33#slots333 #######1de(method#write-object#progn#115objectvar#5name3#5streamvar3 #########1with-slots#51new-class-all-slots#slots#s'perclasses3#5objectvar ###########5P1mapcar#NC1lambda#1)3#1slot-/write-val'e#)#streamvar33#slots333333
Tagged /tructures
With the #bility to de'ine bin#ry cl#!!e! th#t e.tend other bin#ry cl#!!e!, you@re re#dy to de'ine # ne6 *#cro 'or de'ining cl#!!e! to repre!ent Ht#ggedH !tructure!. &he !tr#tegy 'or re#ding t#gged !tructure! 6ill be to de'ine # !peci#liAed read-val'e *ethod th#t 9no6! ho6 to re#d the ?#lue! th#t *#9e up the !t#rt o' the !tructure #nd then u!e tho!e ?#lue! to deter*ine 6h#t !ubcl#!! to in!t#nti#te. It@ll then
*#9e #n in!t#nce o' th#t cl#!! 6ith MA+E-INSTANCE, p#!!ing the #lre#dy re#d ?#lue! #! init#rg!, #nd p#!! the ob<ect to read-object, #llo6ing the #ctu#l cl#!! o' the ob<ect to deter*ine ho6 the re!t o' the !tructure i! re#d. &he ne6 *#cro, de(ine-tagged-binar?-class, 6ill loo9 li9e de(ine-binar?-class 6ith the #ddition o' # :dispatch option u!ed to !peci'y # 'or* th#t !hould e?#lu#te to the n#*e o' # bin#ry cl#!!. &he :dispatch 'or* 6ill be e?#lu#ted in # conte.t 6here the n#*e! o' the !lot! de'ined by the t#gged cl#!! #re bound to ?#ri#ble! th#t hold the ?#lue! re#d 'ro* the 'ile. &he cl#!! 6ho!e n#*e it return! *u!t #ccept init#rg! corre!ponding to the !lot n#*e! de'ined by the t#gged cl#!!. &hi! i! e#!ily en!ured i' the :dispatch 'or* #l6#y! e?#lu#te! to the n#*e o' # cl#!! th#t !ubcl#!!e! the t#gged cl#!!. /or in!t#nce, !uppo!ing you h#?e # 'unction, (ind-(rame-class, th#t 6ill *#p # !tring identi'ier to # bin#ry cl#!! repre!enting # p#rticul#r 9ind o' I+3 'r#*e, you *ight de'ine # t#gged bin#ry cl#!!, id3-(rame, li9e thi!:
1de(ine-tagged-binar?-class#id3-(rame#13 ##11id###1iso-RR"9-0-string#:length#333 ###1si*e#'333 ##1:dispatch#1(ind-(rame-class#id333
&he e.p#n!ion o' # de(ine-tagged-binar?-class 6ill cont#in # DEFCLASS #nd # writeobject *ethod <u!t li9e the e.p#n!ion o' de(ine-binar?-class, but in!te#d o' # readobject *ethod it@ll cont#in # read-val'e *ethod th#t loo9! li9e thi!:
1de(method#read-val'e#11t?pe#1e@l#Cid3-(rame33#stream#>&e?3 ##1let#11id#1read-val'e#Ciso-RR"9-0-string#stream#:length#333 ########1si*e#1read-val'e#C'3#stream333 ####1let#11object#1ma&e-instance#1(ind-(rame-class#id3#:id#id#:si*e#si*e333 ######1read-object#object#stream3 ######object333
Since the e.p#n!ion! o' de(ine-tagged-binar?-class #nd de(ine-binar?-class #re going to be identic#l e.cept 'or the re#d *ethod, you c#n '#ctor out the co**on bit! into # helper *#cro, de(ine-generic-binar?-class, th#t #ccept! the re#d *ethod #! # p#r#*eter #nd interpol#te! it.
1de(macro#de(ine-generic-binar?-class#1name#1>rest#s'perclasses3#slots#readmethod3 ##1with-gens?ms#1objectvar#streamvar3 ####B1progn #######1eval-when#1:compile-toplevel#:load-toplevel#:e)ec'te3 #########1set(#1get#C5name#Cslots3#C51mapcar#NC(irst#slots33 #########1set(#1get#C5name#Cs'perclasses3#C5s'perclasses33 #######1de(class#5name#5s'perclasses #########51mapcar#NCslot-/de(class-slot#slots33 #######5read-method #######1de(method#write-object#progn#115objectvar#5name3#5streamvar3 #########1declare#1ignorable#5streamvar33 #########1with-slots#51new-class-all-slots#slots#s'perclasses3#5objectvar ###########5P1mapcar#NC1lambda#1)3#1slot-/write-val'e#)#streamvar33#slots333333
:o6 you c#n de'ine both de(ine-binar?-class #nd de(ine-tagged-binar?-class to e.p#nd into # c#ll to de(ine-generic-binar?-class. >ere@! # ne6 ?er!ion o' de(inebinar?-class th#t gener#te! the !#*e code #! the e#rlier ?er!ion 6hen it@! 'ully e.p#nded:
1de(macro#de(ine-binar?-class#1name#1>rest#s'perclasses3#slots3 ##1with-gens?ms#1objectvar#streamvar3 ####B1de(ine-generic-binar?-class#5name#5s'perclasses#5slots #######1de(method#read-object#progn#115objectvar#5name3#5streamvar3 #########1declare#1ignorable#5streamvar33 #########1with-slots#51new-class-all-slots#slots#s'perclasses3#5objectvar ###########5P1mapcar#NC1lambda#1)3#1slot-/read-val'e#)#streamvar33#slots333333
%nd here@! de(ine-tagged-binar?-class #long 6ith t6o ne6 helper 'unction! it u!e!:
1de(macro#de(ine-tagged-binar?-class#1name#1>rest#s'perclasses3#slots#>rest# options3 ##1with-gens?ms#1t?pevar#objectvar#streamvar3 ####B1de(ine-generic-binar?-class#5name#5s'perclasses#5slots ######1de(method#read-val'e#115t?pevar#1e@l#C5name33#5streamvar#>&e?3 ########1letU#51mapcar#NC1lambda#1)3#1slot-/binding#)#streamvar33#slots3 ##########1let#115objectvar #################1ma&e-instance# ##################5P1or#1cdr#1assoc#:dispatch#options33 ########################1error#4%'st#s'ppl?#:dispatch#(orm.433 ##################5P1mapcan#NCslot-/&e?word-arg#slots3333 ############1read-object#5objectvar#5streamvar3 ############5objectvar333333 1de('n#slot-/binding#1spec#stream3 ##1destr'ct'ring-bind#1name#1t?pe#>rest#args33#1normali*e-slot-spec#spec3 ####B15name#1read-val'e#C5t?pe#5stream#5Pargs3333 1de('n#slot-/&e?word-arg#1spec3 ##1let#11name#1(irst#spec333 ####B151as-&e?word#name3#5name333
So you !hould de'ine one l#!t *#cro, de(ine-binar?-t?pe, th#t 6ill gener#te read-val'e #nd write-val'e *ethod! 'or re#ding ?#lue! repre!ented by in!t#nce! o' e.i!ting cl#!!e!, r#ther th#n by cl#!!e! de'ined 6ith de(ine-binar?-class. /or # concrete e.#*ple, con!ider # type u!ed in the id3-tag cl#!!, # 'i.ed-length !tring encoded in IS5-,,5)-1 ch#r#cter!. I@ll #!!u*e, #! I did e#rlier, th#t the n#ti?e ch#r#cter encoding o' your i!p i! IS5-,,5)-1 or # !uper!et, !o you c#n u!e CODE-CHAR #nd CHAR-CODE to tr#n!l#te byte! to ch#r#cter! #nd b#c9. %! #l6#y!, your go#l i! to 6rite # *#cro th#t #llo6! you to e.pre!! only the e!!enti#l in'or*#tion needed to gener#te the reFuired code. In thi! c#!e, there #re 'our piece! o' e!!enti#l in'or*#tion: the n#*e o' the type, iso-RR"9-0-stringG the &)'* p#r#*eter! th#t !hould be #ccepted by the read-val'e #nd write-val'e *ethod!, length in thi! c#!eG the code 'or re#ding 'ro* # !tre#*G #nd the code 'or 6riting to # !tre#*. >ere@! #n e.pre!!ion th#t cont#in! tho!e 'our piece! o' in'or*#tion:
1de(ine-binar?-t?pe#iso-RR"9-0-string#1length3 ##1:reader#1in3 ####1let#11string#1ma&e-string#length333 ######1dotimes#1i#length3 ########1set(#1char#string#i3#1code-char#1read-b?te#in3333 ######string33 ##1:writer#1o't#string3 ####1dotimes#1i#length3 ######1write-b?te#1char-code#1char#string#i33#o't3333
:o6 you <u!t need # *#cro th#t c#n t#9e #p#rt thi! 'or* #nd put it b#c9 together in the 'or* o' t6o DEFMETHOD! 6r#pped in # PROGN. I' you de'ine the p#r#*eter li!t to de(ine-binar?-t?pe li9e thi!:
#1de(macro#de(ine-binar?-t?pe#1name#1>rest#args3#>bod?#spec3#...
then 6ithin the *#cro the p#r#*eter spec 6ill be # li!t cont#ining the re#der #nd 6riter de'inition!. 4ou c#n then u!e ASSOC to e.tr#ct the ele*ent! o' spec u!ing the t#g! :reader #nd :writer #nd then u!e DESTRUCTURING-BIND to t#9e #p#rt the REST o' e#ch ele*ent.10 /ro* there it@! <u!t # *#tter o' interpol#ting the e.tr#cted ?#lue! into the b#c9Fuoted te*pl#te! o' the read-val'e #nd write-val'e *ethod!.
1de(macro#de(ine-binar?-t?pe#1name#1>rest#args3#>bod?#spec3 ##1with-gens?ms#1t?pe3 ####B1progn ######51destr'ct'ring-bind#11in3#>bod?#bod?3#1rest#1assoc#:reader#spec33 ########B1de(method#read-val'e#115t?pe#1e@l#C5name33#5in#>&e?#5Pargs3 ##########5Pbod?33 ######51destr'ct'ring-bind#11o't#val'e3#>bod?#bod?3#1rest#1assoc#:writer#spec33 ########B1de(method#write-val'e#115t?pe#1e@l#C5name33#5o't#5val'e#>&e?#5Pargs3 ##########5Pbod?33333
:ote ho6 the b#c9Fuoted te*pl#te! #re ne!ted: the outer*o!t te*pl#te !t#rt! 6ith the b#c9Fuoted PROGN 'or*. &h#t te*pl#te con!i!t! o' the !y*bol PROGN #nd t6o co**#-unFuoted DESTRUCTURING-BIND e.pre!!ion!. &hu!, the outer te*pl#te i! 'illed in by e?#lu#ting the DESTRUCTURING-BIND e.pre!!ion! #nd interpol#ting their ?#lue!. (#ch DESTRUCTURING-BIND e.pre!!ion in turn cont#in! #nother b#c9Fuoted te*pl#te, 6hich i! u!ed to gener#te one o' the *ethod de'inition! to be interpol#ted in the outer te*pl#te.
With thi! *#cro de'ined, the de(ine-binar?-t?pe 'or* gi?en pre?iou!ly e.p#nd! to thi! code:
1progn ##1de(method#read-val'e#11N:g060R#1e@l#Ciso-RR"9-0-string33#in#>&e?#length3 ####1let#11string#1ma&e-string#length333 ######1dotimes#1i#length3 ########1set(#1char#string#i3#1code-char#1read-b?te#in3333 ######string33 ##1de(method#write-val'e#11N:g060R#1e@l#Ciso-RR"9-0-string33#o't#string#>&e?# length3 ####1dotimes#1i#length3 ######1write-b?te#1char-code#1char#string#i33#o't3333
5' cour!e, no6 th#t you@?e got thi! nice *#cro 'or de'ining bin#ry type!, it@! te*pting to *#9e it do # bit *ore 6or9. /or no6 you !hould <u!t *#9e one !*#ll enh#nce*ent th#t 6ill turn out to be pretty h#ndy 6hen you !t#rt u!ing thi! libr#ry to de#l 6ith #ctu#l 'or*#t! !uch #! I+3 t#g!. I+3 t#g!, li9e *#ny other bin#ry 'or*#t!, u!e lot! o' pri*iti?e type! th#t #re *inor ?#ri#tion! on # the*e, !uch #! un!igned integer! in one-, t6o-, three-, #nd 'our-byte ?#rietie!. 4ou could cert#inly de'ine e#ch o' tho!e type! 6ith de(ine-binar?-t?pe #! it !t#nd!. 5r you could '#ctor out the co**on #lgorith* 'or re#ding #nd 6riting n-byte un!igned integer! into helper 'unction!. 7ut !uppo!e you h#d #lre#dy de'ined # bin#ry type, 'nsigned-integer, th#t #ccept! # :b?tes p#r#*eter to !peci'y ho6 *#ny byte! to re#d #nd 6rite. 8!ing th#t type, you could !peci'y # !lot repre!enting # one-byte un!igned integer 6ith # type !peci'ier o' 1'nsigned-integer#:b?tes# 03. 7ut i' # p#rticul#r bin#ry 'or*#t !peci'ie! lot! o' !lot! o' th#t type, it@d be nice to be #ble to e#!ily de'ine # ne6 type--!#y, '0--th#t *e#n! the !#*e thing. %! it turn! out, it@! e#!y to ch#nge de(inebinar?-t?pe to !upport t6o 'or*!, # long 'or* con!i!ting o' # :reader #nd :writer p#ir #nd # !hort 'or* th#t de'ine! # ne6 bin#ry type in ter*! o' #n e.i!ting type. 8!ing # !hort 'or* de(inebinar?-t?pe, you c#n de'ine '0 li9e thi!:
1de(ine-binar?-t?pe#'0#13#1'nsigned-integer#:b?tes#033
&o !upport both long- #nd !hort-'or* de(ine-binar?-t?pe c#ll!, you need to di''erenti#te b#!ed on the ?#lue o' the spec #rgu*ent. I' spec i! t6o ite*! long, it repre!ent! # long-'or* c#ll, #nd the t6o ite*! !hould be the :reader #nd :writer !peci'ic#tion!, 6hich you e.tr#ct #! be'ore. 5n the other h#nd, i' it@! only one ite* long, the one ite* !hould be # type !peci'ier, 6hich need! to be p#r!ed di''erently. 4ou c#n u!e ECASE to !6itch on the LENGTH o' spec #nd then p#r!e spec #nd gener#te #n #ppropri#te e.p#n!ion 'or either the long 'or* or the !hort 'or*.
1de(macro#de(ine-binar?-t?pe#1name#1>rest#args3#>bod?#spec3 ##1ecase#1length#spec3 ####10 #####1with-gens?ms#1t?pe#stream#val'e3 #######1destr'ct'ring-bind#1derived-(rom#>rest#derived-args3#1m&list#1(irst#spec33 #########B1progn ############1de(method#read-val'e#115t?pe#1e@l#C5name33#5stream#>&e?#5Pargs3
##############1read-val'e#C5derived-(rom#5stream#5Pderived-args33 ############1de(method#write-val'e#115t?pe#1e@l#C5name33#5stream#5val'e#>&e?# 5Pargs3 ##############1write-val'e#C5derived-(rom#5stream#5val'e#5Pderived-args333333 ####1! #####1with-gens?ms#1t?pe3 #######B1progn ##########51destr'ct'ring-bind#11in3#>bod?#bod?3#1rest#1assoc#:reader#spec33 #############B1de(method#read-val'e#115t?pe#1e@l#C5name33#5in#>&e?#5Pargs3 ################5Pbod?33 ##########51destr'ct'ring-bind#11o't#val'e3#>bod?#bod?3#1rest#1assoc#:writer# spec33 #############B1de(method#write-val'e#115t?pe#1e@l#C5name33#5o't#5val'e#>&e?# 5Pargs3 ################5Pbod?3333333
&hen you c#n de'ine :aro'nd *ethod! on read-object #nd write-object th#t pu!h the ob<ect being re#d or 6ritten onto thi! ?#ri#ble be'ore in?o9ing CALL-NEXT-METHOD.
1de(method#read-object#:aro'nd#1object#stream3 ##1declare#1ignore#stream33 ##1let#11Uin-progress-objectsU#1cons#object#Uin-progress-objectsU333 ####1call-ne)t-method333 1de(method#write-object#:aro'nd#1object#stream3 ##1declare#1ignore#stream33 ##1let#11Uin-progress-objectsU#1cons#object#Uin-progress-objectsU333 ####1call-ne)t-method333
:ote ho6 you rebind Uin-progress-objectsU to # li!t 6ith # ne6 ite* on the 'ront r#ther th#n #!!igning it # ne6 ?#lue. &hi! 6#y, #t the end o' the LET, #'ter CALL-NEXT-METHOD return!, the old ?#lue o' Uin-progress-objectsU 6ill be re!tored, e''ecti?ely popping the ob<ect o' the !t#c9. With tho!e t6o *ethod! de'ined, you c#n pro?ide t6o con?enience 'unction! 'or getting #t !peci'ic ob<ect! in the in-progre!! !t#c9. &he 'unction c'rrent-binar?-object 6ill return the he#d o' the !t#c9, the ob<ect 6ho!e read-object or write-object *ethod 6#! in?o9ed *o!t recently. &he other, parent-o(-t?pe, t#9e! #n #rgu*ent th#t !hould be the n#*e o' # bin#ry ob<ect cl#!! #nd return! the *o!t recently pu!hed ob<ect o' th#t type, u!ing the TYPEP 'unction th#t te!t! 6hether # gi?en ob<ect i! #n in!t#nce o' # p#rticul#r type.
1de('n#c'rrent-binar?-object#13#1(irst#Uin-progress-objectsU33 1de('n#parent-o(-t?pe#1t?pe3
##1(ind-i(#NC1lambda#1)3#1t?pep#)#t?pe33#Uin-progress-objectsU33
&he!e t6o 'unction! c#n be u!ed in #ny code th#t 6ill be c#lled 6ithin the dyn#*ic e.tent o' # readobject or write-object c#ll. 4ou@ll !ee one e.#*ple o' ho6 c'rrent-binar?-object c#n be u!ed in the ne.t ch#pter.11 :o6 you h#?e #ll the tool! you need to t#c9le #n I+3 p#r!ing libr#ry, !o you@re re#dy to *o?e onto the ne.t ch#pter 6here you@ll do <u!t th#t.
1In %SCII,
the 'ir!t 32 ch#r#cter! #re nonprinting control characters origin#lly u!ed to control the beh#?ior o' # &eletype *#chine, c#u!ing it to do !uch thing! #! !ound the bell, b#c9 up one ch#r#cter, *o?e to # ne6 line, #nd *o?e the c#rri#ge to the beginning o' the line. 5' the!e 32 control ch#r#cter!, only three, the ne6line, c#rri#ge return, #nd horiAont#l t#b, #re typic#lly 'ound in te.t 'ile!.
2So*e
bin#ry 'ile 'or*#t! are in-*e*ory d#t# !tructure!--on *#ny oper#ting !y!te*! it@! po!!ible to *#p # 'ile into *e*ory, #nd lo6-le?el l#ngu#ge! !uch #! C c#n then tre#t the region o' *e*ory cont#ining the content! o' the 'ile <u!t li9e #ny other *e*oryG d#t# 6ritten to th#t #re# o' *e*ory i! !#?ed to the underlying 'ile 6hen it@! un*#pped. >o6e?er, the!e 'or*#t! #re pl#t'or*-dependent !ince the in-*e*ory repre!ent#tion o' e?en !uch !i*ple d#t# type! #! integer! depend! on the h#rd6#re on 6hich the progr#* i! running. &hu!, #ny 'ile 'or*#t th#t@! intended to be port#ble *u!t de'ine # c#nonic#l repre!ent#tion 'or #ll the d#t# type! it u!e! th#t c#n be *#pped to the #ctu#l in-*e*ory d#t# repre!ent#tion on # p#rticul#r 9ind o' *#chine or in # p#rticul#r l#ngu#ge.
3&he
ter* big)endian #nd it! oppo!ite, little)endian, borro6ed 'ro* Don#th#n S6i't@! Dulliver(s Travels, re'er to the 6#y # *ultibyte nu*ber i! repre!ented in #n ordered !eFuence o' byte! !uch #! in *e*ory or in # 'ile. /or in!t#nce, the nu*ber -3),1, or abcd in he., repre!ented #! # 10-bit Fu#ntity, con!i!t! o' t6o byte!, ab #nd cd. It doe!n@t *#tter to # co*puter in 6h#t order the!e t6o byte! #re !tored #! long #! e?erybody #gree!. 5' cour!e, 6hene?er there@! #n #rbitr#ry choice to be *#de bet6een t6o eFu#lly good option!, the one thing you c#n be !ure o' i! th#t e?erybody i! not going to #gree. /or *ore th#n you e?er 6#nted to 9no6 #bout it, #nd to !ee 6here the ter*! big)endian #nd little)endian 6ere 'ir!t #pplied in thi! '#!hion, re#d H5n >oly W#r! #nd # Ple# 'or Pe#ceH by +#nny Cohen, #?#il#ble #t http://&havrinen.lcs.mit.ed'/wollman/ien-03Q.t)t.
-LDB
#nd DPB, # rel#ted 'unction, 6ere n#*ed #'ter the +(C P+P-10 #!!e*bly 'unction! th#t did e!!enti#lly the !#*e thing. 7oth 'unction! oper#te on integer! #! i' they 6ere repre!ented u!ing t6o!co*ple*ent 'or*#t, reg#rdle!! o' the intern#l repre!ent#tion u!ed by # p#rticul#r Co**on i!p i*ple*ent#tion.
5Co**on
i!p #l!o pro?ide! 'unction! 'or !hi'ting #nd *#!9ing the bit! o' integer! in # 6#y th#t *#y be *ore '#*ili#r to C #nd D#?# progr#**er!. /or in!t#nce, you could 6rite read-'! yet # third 6#y, u!ing tho!e 'unction!, li9e thi!:
1de('n#read-'!#1in3 ##1logior#1ash#1read-b?te#in3#R3#1read-b?te#in333
&he n#*e! LOGIOR #nd ASH #re !hort 'or LODical ;nclusive O* #nd !rithmetic -Bift. ASH !hi't! #n
integer # gi?en nu*ber o' bit! to the le't 6hen it! !econd #rgu*ent i! po!iti?e or to the right i' the !econd #rgu*ent i! neg#ti?e. LOGIOR co*bine! integer! by logic#lly oring e#ch bit. %nother 'unction, LOGAND, per'or*! # bit6i!e and, 6hich c#n be u!ed to *#!9 o'' cert#in bit!. >o6e?er, 'or the 9ind! o' bit t6iddling you@ll need to do in thi! ch#pter #nd the ne.t, LDB #nd BYTE 6ill be both *ore con?enient #nd *ore idio*#tic Co**on i!p !tyle.
05rigin#lly,
8&/-, 6#! de!igned to repre!ent # 31-bit ch#r#cter code #nd u!ed up to !i. byte! per code point. >o6e?er, the *#.i*u* 8nicode code point i! N)0 ((((, !o # 8&/-, encoding o' 8nicode reFuire! #t *o!t 'our byte! per code point.
2I'
you need to p#r!e # 'ile 'or*#t th#t u!e! other ch#r#cter code!, or i' you need to p#r!e 'ile! cont#ining #rbitr#ry 8nicode !tring! u!ing # non-8nicode-Co**on- i!p i*ple*ent#tion, you c#n #l6#y! repre!ent !uch !tring! in *e*ory #! ?ector! o' integer code point!. &hey 6on@t be i!p !tring!, !o you 6on@t be #ble to *#nipul#te or co*p#re the* 6ith the !tring 'unction!, but you@ll !till be #ble to do #nything 6ith the* th#t you c#n 6ith #rbitr#ry ?ector!.
,8n'ortun#tely,
the l#ngu#ge it!el' doe!n@t #l6#y! pro?ide # good *odel in thi! re!pect: the *#cro DEFSTRUCT, 6hich I don@t di!cu!! !ince it h#! l#rgely been !uper!eded by DEFCLASS, gener#te! 'unction! 6ith n#*e! th#t it gener#te! b#!ed on the n#*e o' the !tructure it@! gi?en. DEFSTRUCT@! b#d e.#*ple le#d! *#ny ne6 *#cro 6riter! #!tr#y.
)&echnic#lly
there@! no po!!ibility o' t?pe or object con'licting 6ith !lot n#*e!--#t 6or!t they@d be !h#do6ed 6ithin the WITH-SLOTS 'or*. 7ut it doe!n@t hurt #nything to !i*ply GENSYM #ll loc#l ?#ri#ble n#*e! u!ed 6ithin # *#cro te*pl#te.
108!ing
ASSOC to e.tr#ct the :reader #nd :writer ele*ent! o' spec #llo6! u!er! o' de(inebinar?-t?pe to include the ele*ent! in either orderG i' you reFuired the :reader ele*ent to be #l6#y! be 'ir!t, you could then h#?e u!ed 1rest#1(irst#spec33 to e.tr#ct the re#der #nd 1rest# 1second#spec33 to e.tr#ct the 6riter. >o6e?er, #! long #! you reFuire the :reader #nd :writer 9ey6ord! to i*pro?e the re#d#bility o' de(ine-binar?-t?pe 'or*!, you *ight #! 6ell u!e the* to e.tr#ct the correct d#t#.
11&he
I+3 'or*#t doe!n@t reFuire the parent-o(-t?pe 'unction !ince it@! # rel#ti?ely 'l#t !tructure. &hi! 'unction co*e! into it! o6n 6hen you need to p#r!e # 'or*#t *#de up o' *#ny deeply ne!ted !tructure! 6ho!e p#r!ing depend! on in'or*#tion !tored in higher-le?el !tructure!. /or e.#*ple, in the D#?# cl#!! 'ile 'or*#t, the top-le?el cl#!! 'ile !tructure cont#in! # constant pool th#t *#p! nu*eric ?#lue! u!ed in other !ub!tructure! 6ithin the cl#!! 'ile to con!t#nt ?#lue! th#t #re needed 6hile p#r!ing tho!e !ub!tructure!. I' you 6ere 6riting # cl#!! 'ile p#r!er, you could u!e parent-o(-t?pe in the code th#t re#d! #nd 6rite! tho!e !ub!tructure! to get #t the top-le?el cl#!! 'ile ob<ect #nd 'ro* there to the con!t#nt pool.
o' the Intern#tion#l 5rg#niA#tion 'or St#nd#rdiA#tion BIS5C #nd the Intern#tion#l (lectrotechnic#l Co**i!!ion BI(CC. >o6e?er, the 3P3 'or*#t, by it!el', de'ine! only ho6 to !tore #udio d#t#. &h#t@! 'ine #! long #! #ll your 3P3 'ile! #re *#n#ged by # !ingle #pplic#tion th#t c#n !tore *et#d#t# e.tern#lly #nd 9eep tr#c9 o' 6hich *et#d#t# goe! 6ith 6hich 'ile!. >o6e?er, 6hen people !t#rted p#!!ing #round indi?idu#l 3P3 'ile! on the Internet, ?i# 'ile-!h#ring !y!te*! !uch #! :#p!ter, they !oon di!co?ered they needed # 6#y to e*bed *et#d#t# in the 3P3 'ile! the*!el?e!. 7ec#u!e the 3P3 !t#nd#rd 6#! #lre#dy codi'ied #nd # '#ir bit o' !o't6#re #nd h#rd6#re h#d #lre#dy been 6ritten th#t 9ne6 ho6 to decode the e.i!ting 3P3 'or*#t, #ny !che*e 'or e*bedding in'or*#tion in #n 3P3 'ile 6ould h#?e to be in?i!ible to 3P3 decoder!. (nter I+3. &he origin#l I+3 'or*#t, in?ented by progr#**er (ric Le*p, con!i!ted o' 12, byte! !tuc9 on the end o' #n 3P3 'ile 6here it@d be ignored by *o!t 3P3 !o't6#re. It con!i!ted o' 'our 30-ch#r#cter 'ield!, one e#ch 'or the !ong title, the #lbu* title, the #rti!t n#*e, #nd # co**entG # 'our-byte ye#r 'ieldG #nd # one-byte genre code. Le*p pro?ided !t#nd#rd *e#ning! 'or the 'ir!t ,0 genre code!. :ull!o't, the *#9er! o' Win#*p, # popul#r 3P3 pl#yer, l#ter !upple*ented thi! li!t 6ith #nother 00 or !o genre!. &hi! 'or*#t 6#! e#!y to p#r!e but ob?iou!ly Fuite li*ited. It h#d no 6#y to encode n#*e! longer th#n 30 ch#r#cter!G it 6#! li*ited to 250 genre!, #nd the *e#ning o' the genre code! h#d to be #greed upon by #ll u!er! o' I+3-#6#re !o't6#re. &here 6#!n@t e?en # 6#y to encode the C+ tr#c9 nu*ber o' # p#rticul#r 3P3 'ile until #nother progr#**er, 3ich#el 3ut!chler, propo!ed e*bedding the tr#c9 nu*ber in the co**ent 'ield, !ep#r#ted 'ro* the re!t o' the co**ent by # null byte, !o e.i!ting I+3 !o't6#re, 6hich tended to re#d up to the 'ir!t null in e#ch o' the te.t 'ield!, 6ould ignore it. Le*p@! ?er!ion i! no6 c#lled I+3?1, #nd 3ut!chler@! i! I+3?1.1. i*ited #! they 6ere, the ?er!ion 1 propo!#l! 6ere #t le#!t # p#rti#l !olution to the *et#d#t# proble*, !o they 6ere #dopted by *#ny 3P3 ripping progr#*! B6hich h#d to put the I+3 t#g into the 3P3 'ile!C #nd 3P3 pl#yer! B6hich 6ould e.tr#ct the in'or*#tion in the I+3 t#g to di!pl#y to the u!erC.1 7y 1)),, ho6e?er, the li*it#tion! 6ere re#lly beco*ing #nnoying, #nd # ne6 group, led by 3#rtin :il!!on, !t#rted 6or9 on # co*pletely ne6 t#gging !che*e, 6hich c#*e to be c#lled I+3?2. &he I+3?2 'or*#t i! e.tre*ely 'le.ible, #llo6ing 'or *#ny 9ind! o' in'or*#tion to be included, 6ith #l*o!t no length li*it#tion!. It #l!o t#9e! #d?#nt#ge o' cert#in det#il! o' the 3P3 'or*#t to #llo6 I+3?2 t#g! to be pl#ced #t the beginning o' #n 3P3 'ile. I+3?2 t#g! #re, ho6e?er, *ore o' # ch#llenge to p#r!e th#n ?er!ion 1 t#g!. In thi! ch#pter, you@ll u!e the bin#ry d#t# p#r!ing libr#ry 'ro* the pre?iou! ch#pter to de?elop code th#t c#n re#d #nd 6rite I+3?2 t#g!. 5r #t le#!t you@ll *#9e # re#!on#ble !t#rt--6here I+3?1 6#! too !i*ple, I+3?2 i! b#roFue to the point o' being co*pletely o?erengineered. I*ple*enting e?ery noo9 #nd cr#nny o' the !peci'ic#tion, e!peci#lly i' you 6#nt to !upport #ll three ?er!ion! th#t h#?e been !peci'ied, 6ould be # '#ir bit o' 6or9. >o6e?er, you c#n ignore *#ny o' the 'e#ture! in tho!e !peci'ic#tion! !ince they@re r#rely u!ed Hin the 6ild.H /or !t#rter!, you c#n ignore, 'or no6, # 6hole ?er!ion, 2.-, !ince it h#! not been 6idely #dopted #nd *o!tly <u!t #dd! *ore needle!! 'le.ibility co*p#red to ?er!ion 2.3. I@ll 'ocu! on ?er!ion! 2.2 #nd 2.3 bec#u!e they@re both 6idely u!ed #nd #re di''erent enough 'ro* e#ch other to 9eep thing! intere!ting.
the t#g purport! to con'or*. &hey@re 'ollo6ed by # !ingle byte 6ho!e indi?idu#l bit! #re tre#ted #! 'l#g!. &he *e#ning! o' the indi?idu#l 'l#g! depend on the ?er!ion o' the !pec. So*e o' the 'l#g! c#n #''ect the 6#y the re!t o' the t#g i! p#r!ed. &he H*#<or ?er!ionH i! #ctu#lly u!ed to record the *inor ?er!ion o' the !pec, 6hile the Hre?i!ionH i! the !ub*inor ?er!ion o' the !pec. &hu!, the H*#<or ?er!ionH 'ield 'or # t#g con'or*ing to the 2.3.0 !pec i! 3. &he re?i!ion 'ield i! #l6#y! Aero !ince e#ch ne6 I+3?2 !pec h#! bu*ped the *inor ?er!ion, le#?ing the !ub*inor ?er!ion #t Aero. &he ?#lue !tored in the *#<or ?er!ion 'ield o' the t#g h#!, #! you@ll !ee, # dr#*#tic e''ect on ho6 you@ll p#r!e the re!t o' the t#g. &he l#!t 'ield in the t#g he#der i! #n integer, encoded in 'our byte! but u!ing only !e?en bit! 'ro* e#ch byte, th#t gi?e! the tot#l !iAe o' the t#g, not counting the he#der. In ?er!ion 2.3 t#g!, the he#der *#y be 'ollo6ed by !e?er#l e3tended header 'ield!G other6i!e, the re*#inder o' the t#g d#t# i! di?ided into frames. +i''erent type! o' 'r#*e! !tore di''erent 9ind! o' in'or*#tion, 'ro* !i*ple te.tu#l in'or*#tion, !uch #! the !ong n#*e, to e*bedded i*#ge!. (#ch 'r#*e !t#rt! 6ith # he#der cont#ining # !tring identi'ier #nd # !iAe. In ?er!ion 2.3, the 'r#*e he#der #l!o cont#in! t6o byte! 6orth o' 'l#g! #nd, depending on the ?#lue o' one the 'l#g!, #n option#l one-byte code indic#ting ho6 the re!t o' the 'r#*e i! encrypted. /r#*e! #re # per'ect e.#*ple o' # t#gged d#t# !tructure--to 9no6 ho6 to p#r!e the body o' # 'r#*e, you need to re#d the he#der #nd u!e the identi'ier to deter*ine 6h#t 9ind o' 'r#*e you@re re#ding. &he I+3 t#g he#der cont#in! no direct indic#tion o' ho6 *#ny 'r#*e! #re in # t#g--the t#g he#der tell! you ho6 big the t#g i!, but !ince *#ny 'r#*e! #re ?#ri#ble length, the only 6#y to 'ind out ho6 *#ny 'r#*e! the t#g cont#in! i! to re#d the 'r#*e d#t#. %l!o, the !iAe gi?en in the t#g he#der *#y be l#rger th#n the #ctu#l nu*ber o' byte! o' 'r#*e d#t#G the 'r#*e! *#y be 'ollo6ed 6ith enough null byte! to p#d the t#g out to the !peci'ied !iAe. &hi! *#9e! it po!!ible 'or t#g editor! to *odi'y # t#g 6ithout h#?ing to re6rite the 6hole 3P3 'ile.2 So, the *#in i!!ue! you h#?e to de#l 6ith #re re#ding the I+3 he#derG deter*ining 6hether you@re re#ding # ?er!ion 2.2 or 2.3 t#gG #nd re#ding the 'r#*e d#t#, !topping either 6hen you@?e re#d the co*plete t#g or 6hen you@?e hit the p#dding byte!.
1e ining a "ackage
i9e the other libr#rie! you@?e de?eloped !o '#r, the code you@ll 6rite in thi! ch#pter i! 6orth putting in it! o6n p#c9#ge. 4ou@ll need to re'er to 'unction! 'ro* both the bin#ry d#t# #nd p#thn#*e libr#rie! de?eloped in Ch#pter! 2- #nd 15 #nd 6ill #l!o 6#nt to e.port the n#*e! o' the 'unction! th#t *#9e up the public %PI to thi! p#c9#ge. &he 'ollo6ing p#c9#ge de'inition doe! #ll th#t:
1de(pac&age#:com.gigamon&e?s.id3v! ##1:'se#:common-lisp ########:com.gigamon&e?s.binar?-data ########:com.gigamon&e?s.pathnames3 ##1:e)port ###:read-id3 ###:mp3-p ###:id3-p ###:alb'm ###:composer ###:genre ###:encoding-program ###:artist ###:part-o(-set ###:trac& ###:song
%! u!u#l, you c#n, #nd prob#bly !hould, ch#nge the com.gigamon&e?s p#rt o' the p#c9#ge n#*e to your o6n do*#in.
Integer Types
4ou c#n !t#rt by de'ining bin#ry type! 'or re#ding #nd 6riting !e?er#l o' the pri*iti?e type! u!ed by the I+3 'or*#t, ?#riou! !iAe! o' un!igned integer!, #nd 'our 9ind! o' !tring!. I+3 u!e! un!igned integer! encoded in one, t6o, three, #nd 'our byte!. I' you 'ir!t 6rite # gener#l 'nsigned-integer bin#ry type th#t t#9e! the nu*ber o' byte! to re#d #! #n #rgu*ent, you c#n then u!e the !hort 'or* o' de(ine-binar?-t?pe to de'ine the !peci'ic type!. &he gener#l 'nsigned-integer type loo9! li9e thi!:
1de(ine-binar?-t?pe#'nsigned-integer#1b?tes3 ##1:reader#1in3 ####1loop#with#val'e#=# #######(or#low-bit#down(rom#1U#R#10-#b?tes33#to# #b?#R#do #########1set(#1ldb#1b?te#R#low-bit3#val'e3#1read-b?te#in33 #######(inall?#1ret'rn#val'e333 ##1:writer#1o't#val'e3 ####1loop#(or#low-bit#down(rom#1U#R#10-#b?tes33#to# #b?#R #######do#1write-b?te#1ldb#1b?te#R#low-bit3#val'e3#o't3333
:o6 you c#n u!e the !hort 'or* o' de(ine-binar?-t?pe to de'ine one type 'or e#ch !iAe o' integer u!ed in the I+3 'or*#t li9e thi!:
1de(ine-binar?-t?pe#'0#13#1'nsigned-integer#:b?tes#033 1de(ine-binar?-t?pe#'!#13#1'nsigned-integer#:b?tes#!33 1de(ine-binar?-t?pe#'3#13#1'nsigned-integer#:b?tes#333 1de(ine-binar?-t?pe#'4#13#1'nsigned-integer#:b?tes#433
%nother type you@ll need to be #ble to re#d #nd 6rite i! the 2,-bit ?#lue u!ed in the he#der. &hi! !iAe i! encoded u!ing 2, bit! r#ther th#n # *ultiple o' ,, !uch #! 32 bit!, bec#u!e #n I+3 t#g c#n@t cont#in the byte N)(( 'ollo6ed by # byte 6ith the top 3 bit! on bec#u!e th#t p#ttern h#! # !peci#l *e#ning to 3P3 decoder!. :one o' the other 'ield! in the I+3 he#der could po!!ibly cont#in !uch # byte !eFuence, but i' you encoded the t#g !iAe #! # regul#r 'nsigned-integer, it *ight. &o #?oid th#t po!!ibility, the !iAe i! encoded u!ing only the botto* !e?en bit! o' e#ch byte, 6ith the top bit #l6#y! Aero.3 &hu!, it c#n be re#d #nd 6ritten # lot li9e #n 'nsigned-integer e.cept the !iAe o' the byte !peci'ier you p#!! to LDB !hould be !e?en r#ther th#n eight. &hi! !i*il#rity !ugge!t! th#t i' you #dd # p#r#*eter, bits-per-b?te, to the e.i!ting 'nsigned-integer bin#ry type, you could then de'ine # ne6 type, id3-tag-si*e, u!ing # !hort-'or* de(ine-binar?-t?pe. &he ne6 ?er!ion o' 'nsigned-integer i! <u!t li9e the old ?er!ion e.cept 6ith bits-per-b?te u!ed e?ery6here the old ?er!ion h#rd6ired the nu*ber eight. It loo9! li9e thi!:
1de(ine-binar?-t?pe#'nsigned-integer#1b?tes#bits-per-b?te3 ##1:reader#1in3 ####1loop#with#val'e#=# #######(or#low-bit#down(rom#1U#bits-per-b?te#10-#b?tes33#to# #b?#bits-per-b?te#do #########1set(#1ldb#1b?te#bits-per-b?te#low-bit3#val'e3#1read-b?te#in33
4ou@ll #l!o h#?e to ch#nge the de'inition! o' '0 through '4 to !peci'y eight bit! per byte li9e thi!:
1de(ine-binar?-t?pe#'0#13#1'nsigned-integer#:b?tes#0#:bits-per-b?te#R33 1de(ine-binar?-t?pe#'!#13#1'nsigned-integer#:b?tes#!#:bits-per-b?te#R33 1de(ine-binar?-t?pe#'3#13#1'nsigned-integer#:b?tes#3#:bits-per-b?te#R33 1de(ine-binar?-t?pe#'4#13#1'nsigned-integer#:b?tes#4#:bits-per-b?te#R33
/tring Types
&he other 9ind! o' pri*iti?e type! th#t #re ubiFuitou! in the I+3 'or*#t #re !tring!. In the pre?iou! ch#pter I di!cu!!ed !o*e o' the i!!ue! you h#?e to con!ider 6hen de#ling 6ith !tring! in bin#ry 'ile!, !uch #! the di''erence bet6een ch#r#cter code! #nd ch#r#cter encoding!. I+3 u!e! t6o di''erent ch#r#cter code!, IS5 ,,5)-1 #nd 8nicode. IS5 ,,5)-1, #l!o 9no6n #! #tin-1, i! #n eight-bit ch#r#cter code th#t e.tend! %SCII 6ith ch#r#cter! u!ed by the l#ngu#ge! o' We!tern (urope. In other 6ord!, the code point! 'ro* 0-122 *#p to the !#*e ch#r#cter! in %SCII #nd IS5 ,,5)-1, but IS5 ,,5)-1 #l!o pro?ide! *#pping! 'or code point! up to 255. 8nicode i! # ch#r#cter code de!igned to pro?ide # code point 'or ?irtu#lly e?ery ch#r#cter o' #ll the 6orld@! l#ngu#ge!. 8nicode i! # !uper!et o' IS5 ,,5)-1 in the !#*e 6#y th#t IS5 ,,5)-1 i! # !uper!et o' %SCII--the code point! 'ro* 0-255 *#p to the !#*e ch#r#cter! in both IS5 ,,5)-1 #nd 8nicode. B&hu!, 8nicode i! #l!o # !uper!et o' %SCII.C Since IS5 ,,5)-1 i! #n eight-bit ch#r#cter code, it@! encoded u!ing one byte per ch#r#cter. /or 8nicode !tring!, I+3 u!e! the 8CS-2 encoding 6ith # le#ding b0te order mar$.- I@ll di!cu!! 6h#t # byte order *#r9 i! in # *o*ent. $e#ding #nd 6riting the!e t6o encoding! i!n@t # proble*--it@! <u!t # Fue!tion o' re#ding #nd 6riting un!igned integer! in ?#riou! 'or*#t!, #nd you <u!t 'ini!hed 6riting the code to do th#t. &he tric9 i! ho6 you tr#n!l#te tho!e nu*eric ?#lue! to i!p ch#r#cter ob<ect!. &he i!p i*ple*ent#tion you@re u!ing prob#bly u!e! either 8nicode or IS5 ,,5)-1 #! it! intern#l ch#r#cter code. %nd !ince #ll the ?#lue! 'ro* 0-255 *#p to the !#*e ch#r#cter! in both IS5 ,,5)-1 #nd 8nicode, you c#n u!e i!p@! CODE-CHAR #nd CHAR-CODE 'unction! to tr#n!l#te tho!e ?#lue! in both ch#r#cter code!. >o6e?er, i' your i!p !upport! only IS5 ,,5)-1, then you@ll be #ble to repre!ent only the 'ir!t 255 8nicode ch#r#cter! #! i!p ch#r#cter!. In other 6ord!, in !uch # i!p i*ple*ent#tion, i' you try to proce!! #n I+3 t#g th#t u!e! 8nicode !tring! #nd i' #ny o' tho!e !tring! cont#in ch#r#cter! 6ith code point! higher th#n 255, you@ll get #n error 6hen you try to tr#n!l#te the code point to # i!p ch#r#cter. /or no6 I@ll #!!u*e either you@re u!ing # 8nicode-b#!ed i!p or you 6on@t proce!! #ny 'ile! cont#ining ch#r#cter! out!ide the IS5 ,,5)-1 r#nge. &he other i!!ue 6ith encoding !tring! i! ho6 to 9no6 ho6 *#ny byte! to interpret #! ch#r#cter d#t#. I+3 u!e! t6o !tr#tegie! I *entioned in the pre?iou! ch#pter--!o*e !tring! #re ter*in#ted 6ith # null ch#r#cter, 6hile other !tring! occur in po!ition! 6here you c#n deter*ine the nu*ber o' byte! to re#d, either bec#u!e the !tring #t th#t po!ition i! #l6#y! the !#*e length or bec#u!e the !tring i! #t the end o'
# co*po!ite !tructure 6ho!e o?er#ll !iAe you 9no6. :ote, ho6e?er, th#t the nu*ber o' byte! i!n@t nece!!#rily the !#*e #! the nu*ber o' ch#r#cter! in the !tring. Putting #ll the!e ?#ri#tion! together, the I+3 'or*#t u!e! 'our 6#y! to re#d #nd 6rite !tring!--t6o ch#r#cter! cro!!ed 6ith t6o 6#y! o' deli*iting the !tring d#t#. 5b?iou!ly, *uch o' the logic o' re#ding #nd 6riting !tring! 6ill be Fuite !i*il#r. So, you c#n !t#rt by de'ining t6o bin#ry type!, one 'or re#ding !tring! o' # !peci'ic length Bin ch#r#cter!C #nd #nother 'or re#ding ter*in#ted !tring!. 7oth type! t#9e #d?#nt#ge o' th#t the type #rgu*ent to read-val'e #nd write-val'e i! <u!t #nother piece o' d#t#G you c#n *#9e the type o' ch#r#cter to re#d # p#r#*eter o' the!e type!. &hi! i! # techniFue you@ll u!e Fuite # 'e6 ti*e! in thi! ch#pter.
1de(ine-binar?-t?pe#generic-string#1length#character-t?pe3 ##1:reader#1in3 ####1let#11string#1ma&e-string#length333 ######1dotimes#1i#length3 ########1set(#1char#string#i3#1read-val'e#character-t?pe#in333 ######string33 ##1:writer#1o't#string3 ####1dotimes#1i#length3 ######1write-val'e#character-t?pe#o't#1char#string#i33333 1de(ine-binar?-t?pe#generic-terminated-string#1terminator#character-t?pe3 ##1:reader#1in3 ####1with-o'tp't-to-string#1s3 ######1loop#(or#char#=#1read-val'e#character-t?pe#in3 ############'ntil#1char=#char#terminator3#do#1write-char#char#s3333 ##1:writer#1o't#string3 ####1loop#(or#char#across#string ##########do#1write-val'e#character-t?pe#o't#char3 ##########(inall?#1write-val'e#character-t?pe#o't#terminator3333
With the!e type! #?#il#ble, there@! not *uch to re#ding IS5 ,,5)-1 !tring!. 7ec#u!e the charactert?pe #rgu*ent you p#!! to read-val'e #nd write-val'e o' # generic-string *u!t be the n#*e o' # bin#ry type, you need to de'ine #n iso-RR"9-0-char bin#ry type. &hi! #l!o gi?e! you # good pl#ce to put # bit o' !#nity chec9ing on the code point! o' ch#r#cter! you re#d #nd 6rite.
1de(ine-binar?-t?pe#iso-RR"9-0-char#13 ##1:reader#1in3 ####1let#11code#1read-b?te#in333 ######1or#1code-char#code3 ##########1error#4$haracter#code#7d#not#s'pported4#code3333 ##1:writer#1o't#char3 ####1let#11code#1char-code#char333 ######1i(#1O=# #code#N)((3 ##########1write-b?te#code#o't3 ##########1error#49llegal#character#(or#iso-RR"9-0#encoding:#character:#7c#with# code:#7d4#char#code33333
:o6 de'ining the IS5 ,,5)-1 !tring type! i! tri?i#l u!ing the !hort 'or* o' de(ine-binar?-t?pe #! 'ollo6!:
1de(ine-binar?-t?pe#iso-RR"9-0-string#1length3 ##1generic-string#:length#length#:character-t?pe#Ciso-RR"9-0-char33 1de(ine-binar?-t?pe#iso-RR"9-0-terminated-string#1terminator3 ##1generic-terminated-string#:terminator#terminator#:character-t?pe#Ciso-RR"9-0-
char33
$e#ding 8CS-2 !tring! i! only !lightly *ore co*ple.. &he co*ple.ity #ri!e! bec#u!e you c#n encode # 8CS-2 code point in t6o 6#y!: *o!t !igni'ic#nt byte 'ir!t Bbig-endi#nC or le#!t !igni'ic#nt byte 'ir!t Blittle-endi#nC. 8CS-2 !tring! there'ore !t#rt 6ith t6o e.tr# byte!, c#lled the b0te order mar$, *#de up o' the nu*eric ?#lue N)(e(( encoded in either big-endi#n 'or* or little-endi#n 'or*. When re#ding # 8CS-2 !tring, you re#d the byte order *#r9 #nd then, depending on it! ?#lue, re#d either big-endi#n or little-endi#n ch#r#cter!. &hu!, you@ll need t6o di''erent 8CS-2 ch#r#cter type!. 7ut you need only one ?er!ion o' the !#nity-chec9ing code, !o you c#n de'ine # p#r#*eteriAed bin#ry type li9e thi!:
1de(ine-binar?-t?pe#'cs-!-char#1swap3 ##1:reader#1in3 ####1let#11code#1read-val'e#C'!#in333 ######1when#swap#1set(#code#1swap-b?tes#code333 ######1or#1code-char#code3#1error#4$haracter#code#7d#not#s'pported4#code3333 ##1:writer#1o't#char3 ####1let#11code#1char-code#char333 ######1'nless#1O=# #code#N)((((3 ########1error#49llegal#character#(or#'cs-!#encoding:#7c#with#char-code:#7d4#char# code33 ######1when#swap#1set(#code#1swap-b?tes#code333 ######1write-val'e#C'!#o't#code3333
6here the swap-b?tes 'unction c#n be de'ined #! 'ollo6!, t#9ing #d?#nt#ge o' LDB being SETF#ble #nd thu! ROTATEF#ble:
1de('n#swap-b?tes#1code3 ##1assert#1O=#code#N)((((33 ##1rotate(#1ldb#1b?te#R# 3#code3#1ldb#1b?te#R#R3#code33 ##code3
8!ing 'cs-!-char, you c#n de'ine t6o ch#r#cter type! th#t 6ill be u!ed #! the character-t?pe #rgu*ent! to the generic !tring 'unction!.
1de(ine-binar?-t?pe#'cs-!-char-big-endian#13#1'cs-!-char#:swap#nil33 1de(ine-binar?-t?pe#'cs-!-char-little-endian#13#1'cs-!-char#:swap#t33
&hen you need # 'unction th#t return! the n#*e o' the ch#r#cter type to u!e b#!ed on the ?#lue o' the byte order *#r9.
1de('n#'cs-!-char-t?pe#1b?te-order-mar&3 ##1ecase#b?te-order-mar& ####1N)(e((#C'cs-!-char-big-endian3 ####1N)(((e#C'cs-!-char-little-endian333
:o6 you c#n de'ine length- #nd ter*in#tor-deli*ited !tring type! 'or 8CS-2-encoded !tring! th#t re#d the byte order *#r9 #nd u!e it to deter*ine 6hich ?#ri#nt o' 8CS-2 ch#r#cter to p#!! #! the character-t?pe #rgu*ent to read-val'e #nd write-val'e. &he only other 6rin9le i! th#t you need to tr#n!l#te the length #rgu*ent, 6hich i! # nu*ber o' byte!, to the nu*ber o' ch#r#cter! to re#d, #ccounting 'or the byte order *#r9.
1de(ine-binar?-t?pe#'cs-!-string#1length3 ##1:reader#1in3 ####1let#11b?te-order-marread-val'e#C'!#in33 ##########1characters#10-#1/#length#!3333
######1read-val'e #######Cgeneric-string#in #######:length#characters #######:character-t?pe#1'cs-!-char-t?pe#b?te-order-mar&3333 ##1:writer#1o't#string3 ####1write-val'e#C'!#o't#N)(e((3 ####1write-val'e #####Cgeneric-string#o't#string #####:length#1length#string3 #####:character-t?pe#1'cs-!-char-t?pe#N)(e((3333 1de(ine-binar?-t?pe#'cs-!-terminated-string#1terminator3 ##1:reader#1in3 ####1let#11b?te-order-marread-val'e#C'!#in333 ######1read-val'e #######Cgeneric-terminated-string#in #######:terminator#terminator #######:character-t?pe#1'cs-!-char-t?pe#b?te-order-mar&3333 ##1:writer#1o't#string3 ####1write-val'e#C'!#o't#N)(e((3 ####1write-val'e# #####Cgeneric-terminated-string#o't#string #####:terminator#terminator #####:character-t?pe#1'cs-!-char-t?pe#N)(e((3333
'ollo6ed by 'r#*e d#t# #nd p#dding. Since you@?e #lre#dy de'ined bin#ry type! to re#d #nd 6rite #ll the 'ield! in the he#der, de'ining # cl#!! th#t c#n re#d the he#der o' #n I+3 t#g i! <u!t # *#tter o' putting the* together.
1de(ine-binar?-class#id3-tag#13 ##11identi(ier#####1iso-RR"9-0-string#:length#333 ###1major-version##'03 ###1revision#######'03 ###1(lags##########'03 ###1si*e###########id3-tag-si*e333
I' you h#?e !o*e 3P3 'ile! lying #round, you c#n te!t thi! *uch o' the code #nd #l!o !ee 6h#t ?er!ion o' I+3 t#g! your 3P3! cont#in. /ir!t you c#n 6rite # 'unction th#t re#d! #n id3-tag, #! <u!t de'ined, 'ro* the beginning o' # 'ile. 7e #6#re, ho6e?er, th#t I+3 t#g! #ren@t reFuired to #ppe#r #t the beginning o' # 'ile, though the!e d#y! they #l*o!t #l6#y! do. &o 'ind #n I+3 t#g el!e6here in # 'ile, you c#n !c#n the 'ile loo9ing 'or the !eFuence o' byte! 23, 0,, 51 Bin other 6ord!, the !tring HI+3HC.5 /or no6 you c#n prob#bly get #6#y 6ith #!!u*ing the t#g! #re the 'ir!t thing in the 'ile.
5n top o' thi! 'unction you c#n build # 'unction th#t t#9e! # 'ilen#*e #nd print! the in'or*#tion in the t#g he#der #long 6ith the n#*e o' the 'ile.
1de('n#show-tag-header#1(ile3 ##1with-slots#1identi(ier#major-version#revision#(lags#si*e3#1read-id3#(ile3 ####1(ormat#t#47a#7d.7d#7R5C b#7d#b?tes#--#7a764 ############identi(ier#major-version#revision#(lags#si*e#1eno'gh-namestring# (ile3333
5' cour!e, to deter*ine 6h#t ?er!ion! o' I+3 #re *o!t co**on in your 3P3 libr#ry, it@d be h#ndier to h#?e # 'unction th#t return! # !u**#ry o' #ll the 3P3 'ile! under # gi?en directory. 4ou c#n 6rite one e#!ily enough u!ing the wal&-director? 'unction de'ined in Ch#pter 15. /ir!t de'ine # helper 'unction th#t te!t! 6hether # gi?en 'ilen#*e h#! #n mp3 e.ten!ion.
1de('n#mp3-p#1(ile3 ##1and ###1not#1director?-pathname-p#(ile33 ###1string-e@'al#4mp34#1pathname-t?pe#(ile3333
&hen you c#n co*bine show-tag-header #nd mp3-p 6ith wal&-director? to print # !u**#ry o' the I+3 he#der in e#ch 'ile under # gi?en directory.
1de('n#show-tag-headers#1dir3# ##1wal&-director?#dir#NCshow-tag-header#:test#NCmp3-p33
>o6e?er, i' you h#?e # lot o' 3P3!, you *#y <u!t 6#nt # count o' ho6 *#ny I+3 t#g! o' e#ch ?er!ion you h#?e in your 3P3 collection. &o get th#t in'or*#tion, you *ight 6rite # 'unction li9e thi!:
1de('n#co'nt-versions#1dir3 ##1let#11versions#1mapcar#NC1lambda#1)3#1cons#)# 33#C1!#3#43333 ####1(let#11co'nt-version#1(ile3 #############1inc(#1cdr#1assoc#1major-version#1read-id3#(ile33#versions33333 ######1wal&-director?#dir#NCco'nt-version#:test#NCmp3-p33 ####versions33
%nother 'unction you@ll need in Ch#pter 2) i! one th#t te!t! 6hether # 'ile #ctu#lly !t#rt! 6ith #n I+3 t#g, 6hich you c#n de'ine li9e thi!:
1de('n#id3-p#1(ile3 ##1with-open-(ile#1in#(ile#:element-t?pe#C1'nsigned-b?te#R33 ####1string=#49<34#1read-val'e#Ciso-RR"9-0-string#in#:length#33333
I10 Fra$es
%! I di!cu!!ed e#rlier, the bul9 o' #n I+3 t#g i! di?ided into 'r#*e!. (#ch 'r#*e h#! # !tructure !i*il#r
to th#t o' the t#g #! # 6hole. (#ch 'r#*e !t#rt! 6ith # he#der indic#ting 6h#t 9ind o' 'r#*e it i! #nd the !iAe o' the 'r#*e in byte!. &he !tructure o' the 'r#*e he#der ch#nged !lightly bet6een ?er!ion 2.2 #nd ?er!ion 2.3 o' the I+3 'or*#t, #nd e?entu#lly you@ll h#?e to de#l 6ith both 'or*!. &o !t#rt, you c#n 'ocu! on p#r!ing ?er!ion 2.2 'r#*e!. &he he#der o' # 2.2 'r#*e con!i!t! o' three byte! th#t encode # three-ch#r#cter IS5 ,,5)-1 !tring 'ollo6ed by # three-byte un!igned integer, 6hich !peci'ie! the !iAe o' the 'r#*e in byte!, e.cluding the !i.-byte he#der. &he !tring identi'ie! 6h#t type o' 'r#*e it i!, 6hich deter*ine! ho6 you p#r!e the d#t# 'ollo6ing the !iAe. &hi! i! e.#ctly the 9ind o' !itu#tion 'or 6hich you de'ined the de(ine-taggedbinar?-class *#cro. 4ou c#n de'ine # t#gged cl#!! th#t re#d! the 'r#*e he#der #nd then di!p#tche! to the #ppropri#te concrete cl#!! u!ing # 'unction th#t *#p! I+! to # cl#!! n#*e!.
1de(ine-tagged-binar?-class#id3-(rame#13 ##11id#1iso-RR"9-0-string#:length#333 ###1si*e#'333 ##1:dispatch#1(ind-(rame-class#id333
:o6 you@re re#dy to !t#rt i*ple*enting concrete 'r#*e cl#!!e!. >o6e?er, the !peci'ic#tion de'ine! Fuite # 'e6--03 in ?er!ion 2.2 #nd e?en *ore in l#ter !pec!. (?en con!idering 'r#*e type! th#t !h#re # co**on !tructure to be eFui?#lent, you@ll !till 'ind 2- uniFue 'r#*e type! in ?er!ion 2.2. 7ut only # 'e6 o' the!e #re u!ed Hin the 6ild.H So r#ther th#n i**edi#tely !etting to 6or9 de'ining cl#!!e! 'or e#ch o' the 'r#*e type!, you c#n !t#rt by 6riting # generic 'r#*e cl#!! th#t let! you re#d the 'r#*e! in # t#g 6ithout p#r!ing the d#t# 6ithin the 'r#*e! the*!el?e!. &hi! 6ill gi?e you # 6#y to 'ind out 6h#t 'r#*e! #re #ctu#lly pre!ent in the 3P3! you 6#nt to proce!!. 4ou@ll need thi! cl#!! e?entu#lly #ny6#y bec#u!e the !peci'ic#tion #llo6! 'or e.peri*ent#l 'r#*e! th#t you@ll need to be #ble to re#d 6ithout p#r!ing. Since the !iAe 'ield o' the 'r#*e he#der tell! you e.#ctly ho6 *#ny byte! long the 'r#*e i!, you c#n de'ine # generic-(rame cl#!! th#t e.tend! id3-(rame #nd #dd! # !ingle 'ield, data, th#t 6ill hold #n #rr#y o' byte!.
1de(ine-binar?-class#generic-(rame#1id3-(rame3 ##11data#1raw-b?tes#:si*e#si*e3333
&he type o' the d#t# 'ield, raw-b?tes, <u!t need! to hold #n #rr#y o' byte!. 4ou c#n de'ine it li9e thi!:
1de(ine-binar?-t?pe#raw-b?tes#1si*e3 ##1:reader#1in3 ####1let#11b'(#1ma&e-arra?#si*e#:element-t?pe#C1'nsigned-b?te#R3333 ######1read-se@'ence#b'(#in3 ######b'(33 ##1:writer#1o't#b'(3 ####1write-se@'ence#b'(#o't333
/or the ti*e being, you@ll 6#nt #ll 'r#*e! to be re#d #! generic-(rame!, !o you c#n de'ine the (ind-(rame-class 'unction u!ed in id3-(rame@! :dispatch e.pre!!ion to #l6#y! return generic-(rame, reg#rdle!! o' the 'r#*e@! id.
1de('n#(ind-(rame-class#1id3 ##1declare#1ignore#id33 ##Cgeneric-(rame3
:o6 you need to *odi'y id3-tag !o it@ll re#d 'r#*e! #'ter the he#der 'ield!. &here@! only one tric9y bit to re#ding the 'r#*e d#t#: #lthough the t#g he#der tell! you ho6 *#ny byte! long the t#g i!, th#t
nu*ber include! the p#dding th#t c#n 'ollo6 the 'r#*e d#t#. Since the t#g he#der doe!n@t tell you ho6 *#ny 'r#*e! the t#g cont#in!, the only 6#y to tell 6hen you@?e hit the p#dding i! to loo9 'or # null byte 6here you@d e.pect # 'r#*e identi'ier. &o h#ndle thi!, you c#n de'ine # bin#ry type, id3-(rames, th#t 6ill be re!pon!ible 'or re#ding the re*#inder o' # t#g, cre#ting 'r#*e ob<ect! to repre!ent #ll the 'r#*e! it 'ind!, #nd then !9ipping o?er #ny p#dding. &hi! type 6ill t#9e #! # p#r#*eter the t#g !iAe, 6hich it c#n u!e to #?oid re#ding p#!t the end o' the t#g. 7ut the re#ding code 6ill #l!o need to detect the beginning o' the p#dding th#t c#n 'ollo6 the t#g@! 'r#*e d#t#. $#ther th#n c#lling read-val'e directly in id3-(rames :reader, you !hould u!e # 'unction read-(rame, 6hich you@ll de'ine to return NIL 6hen it detect! p#dding, other6i!e returning #n id3-(rame ob<ect re#d u!ing read-val'e. %!!u*ing you de'ine read(rame !o it re#d! only one byte p#!t the end o' the l#!t 'r#*e in order to detect the !t#rt o' the p#dding, you c#n de'ine the id3-(rames bin#ry type li9e thi!:
1de(ine-binar?-t?pe#id3-(rames#1tag-si*e3 ##1:reader#1in3 ####1loop#with#to-read#=#tag-si*e ##########while#1pl'sp#to-read3 ##########(or#(rame#=#1read-(rame#in3 ##########while#(rame ##########do#1dec(#to-read#12#6#1si*e#(rame333 ##########collect#(rame ##########(inall?#1loop#repeat#10-#to-read3#do#1read-b?te#in3333 ##1:writer#1o't#(rames3 ####1loop#with#to-write#=#tag-si*e ##########(or#(rame#in#(rames ##########do#1write-val'e#Cid3-(rame#o't#(rame3 ##########1dec(#to-write#12#6#1si*e#(rame333 ##########(inall?#1loop#repeat#to-write#do#1write-b?te# #o't33333
4ou c#n !t#rt by de'ining # condition type to be !ign#led by the lo6-le?el code #nd h#ndled by the high-le?el code. &hi! condition doe!n@t need #ny !lot!--you <u!t need # di!tinct cl#!! o' condition !o you 9no6 no other code 6ill be !ign#ling or h#ndling it.
1de(ine-condition#in-padding#13#133
:e.t you need to de'ine # bin#ry type 6ho!e :reader re#d! # gi?en nu*ber o' byte!, 'ir!t re#ding # !ingle byte #nd !ign#ling #n in-padding condition i' the byte i! null #nd other6i!e re#ding the re*#ining byte! #! #n iso-RR"9-0-string #nd co*bining it 6ith the 'ir!t byte re#d.
1de(ine-binar?-t?pe#(rame-id#1length3 ##1:reader#1in3 ####1let#11(irst-b?te#1read-b?te#in333 ######1when#1=#(irst-b?te# 3#1signal#Cin-padding33 ######1let#11rest#1read-val'e#Ciso-RR"9-0-string#in#:length#10-#length3333 ########1concatenate #########Cstring#1string#1code-char#(irst-b?te33#rest3333 ##1:writer#1o't#id3 ####1write-val'e#Ciso-RR"9-0-string#o't#id#:length#length333
I' you rede'ine id3-(rame to *#9e the type o' it! id !lot (rame-id in!te#d o' iso-RR"9-0string, the condition 6ill be !ign#led 6hene?er id3-(rame@! read-val'e *ethod re#d! # null byte in!te#d o' the beginning o' # 'r#*e.
1de(ine-tagged-binar?-class#id3-(rame#13 ##11id#1(rame-id#:length#333 ###1si*e#'333 ##1:dispatch#1(ind-(rame-class#id333
:o6 #ll read-(rame h#! to do i! 6r#p # c#ll to read-val'e in # HANDLER-CASE th#t h#ndle! the in-padding condition by returning NIL.
1de('n#read-(rame#1in3 ##1handler-case#1read-val'e#Cid3-(rame#in3 ####1in-padding#13#nil333
With read-(rame de'ined, you c#n no6 re#d # co*plete ?er!ion 2.2 I+3 t#g, repre!enting 'r#*e! 6ith in!t#nce! o' generic-(rame. In the HWh#t /r#*e! +o 4ou %ctu#lly :eed"H !ection, you@ll do !o*e e.peri*ent! #t the $(P to deter*ine 6h#t 'r#*e cl#!!e! you need to i*ple*ent. 7ut 'ir!t let@! #dd !upport 'or ?er!ion 2.3 I+3 t#g!.
1er!ion 2.2 #nd ?er!ion 2.3 t#g! di''er in t6o 6#y!. /ir!t, the he#der o' # ?er!ion 2.3 t#g *#y be e.tended 6ith up to 'our option#l e.tended he#der 'ield!, #! deter*ined by ?#lue! in the 'l#g! 'ield. Second, the 'r#*e 'or*#t ch#nged bet6een ?er!ion 2.2 #nd ?er!ion 2.3, 6hich *e#n! you@ll h#?e to u!e di''erent cl#!!e! to repre!ent ?er!ion 2.2 'r#*e! #nd the corre!ponding ?er!ion 2.3 'r#*e!. Since the ne6 id3-tag cl#!! i! b#!ed on the one you origin#lly 6rote to repre!ent ?er!ion 2.2 t#g!, it@! not !urpri!ing th#t the ne6 id3v!.!-tag cl#!! i! tri?i#l, inheriting *o!t o' it! !lot! 'ro* the ne6 id3-tag cl#!! #nd #dding the one *i!!ing !lot, (rames. 7ec#u!e ?er!ion 2.2 #nd ?er!ion 2.3 t#g! u!e di''erent 'r#*e 'or*#t!, you@ll h#?e to ch#nge the id3-(rames type to be p#r#*eteriAed 6ith the type o' 'r#*e to re#d. /or no6, #!!u*e you@ll do th#t #nd #dd # :(rame-t?pe #rgu*ent to the id3(rames type de!criptor li9e thi!:
1de(ine-binar?-class#id3v!.!-tag#1id3-tag3 ##11(rames#1id3-(rames#:tag-si*e#si*e#:(rame-t?pe#Cid3v!.!-(rame3333
&he id3v!.3-tag cl#!! i! !lightly *ore co*ple. bec#u!e o' the option#l 'ield!. &he 'ir!t three o' the 'our option#l 'ield! #re included 6hen the !i.th bit in (lags i! !et. &hey@re # 'our- byte integer !peci'ying the !iAe o' the e.tended he#der, t6o byte! 6orth o' 'l#g!, #nd #nother 'our-byte integer !peci'ying ho6 *#ny byte! o' p#dding #re included in the t#g.2 &he 'ourth option#l 'ield, included 6hen the 'i'teenth bit o' the e.tended he#der 'l#g! i! !et, i! # 'our-byte cyclic redund#ncy chec9 BC$CC o' the re!t o' the t#g. &he bin#ry d#t# libr#ry doe!n@t pro?ide #ny !peci#l !upport 'or option#l 'ield! in # bin#ry cl#!!, but it turn! out th#t regul#r p#r#*eteriAed bin#ry type! #re !u''icient. 4ou c#n de'ine # type p#r#*eteriAed 6ith the n#*e o' # type #nd # ?#lue th#t indic#te! 6hether # ?#lue o' th#t type !hould #ctu#lly be re#d or 6ritten.
1de(ine-binar?-t?pe#optional#1t?pe#i(3 ##1:reader#1in3 ####1when#i(#1read-val'e#t?pe#in333 ##1:writer#1o't#val'e3 ####1when#i(#1write-val'e#t?pe#o't#val'e3333
8!ing i( #! the p#r#*eter n#*e loo9! # bit !tr#nge in th#t code, but it *#9e! the optional type de!criptor! Fuite re#d#ble. /or in!t#nce, here@! the de'inition o' id3v!.3-tag u!ing optional !lot!:
1de(ine-binar?-class#id3v!.3-tag#1id3-tag3 ##11e)tended-header-si*e#1optional#:t?pe#C'4#:i(#1e)tended-p#(lags333 ###1e)tra-(lags##########1optional#:t?pe#C'!#:i(#1e)tended-p#(lags333 ###1padding-si*e#########1optional#:t?pe#C'4#:i(#1e)tended-p#(lags333 ###1crc##################1optional#:t?pe#C'4#:i(#1crc-p#(lags#e)tra-(lags333 ###1(rames###############1id3-(rames#:tag-si*e#si*e#:(rame-t?pe#Cid3v!.3-(rame3333
6here e)tended-p #nd crc-p #re helper 'unction! th#t te!t the #ppropri#te bit o' the 'l#g! ?#lue they@re p#!!ed. &o te!t 6hether #n indi?idu#l bit o' #n integer i! !et, you c#n u!e LOGBITP, #nother bitt6iddling 'unction. It t#9e! #n inde. #nd #n integer #nd return! true i' the !peci'ied bit i! !et in the integer.
%! in the ?er!ion 2.2 t#g cl#!!, the 'r#*e! !lot i! de'ined to be o' type id3-(rames, p#!!ing the n#*e o' the 'r#*e type #! # p#r#*eter. 4ou do, ho6e?er, need to *#9e # 'e6 !*#ll ch#nge! to id3-(rames# #nd read-(rame to !upport the e.tr# (rame-t?pe p#r#*eter.
1de(ine-binar?-t?pe#id3-(rames#1tag-si*e#(rame-t?pe3 ##1:reader#1in3 ####1loop#with#to-read#=#tag-si*e ##########while#1pl'sp#to-read3 ##########(or#(rame#=#1read-(rame#(rame-t?pe#in3 ##########while#(rame ##########do#1dec(#to-read#12#1(rame-header-si*e#(rame3#1si*e#(rame333 ##########collect#(rame ##########(inall?#1loop#repeat#10-#to-read3#do#1read-b?te#in3333 ##1:writer#1o't#(rames3 ####1loop#with#to-write#=#tag-si*e ##########(or#(rame#in#(rames ##########do#1write-val'e#(rame-t?pe#o't#(rame3 ##########1dec(#to-write#12#1(rame-header-si*e#(rame3#1si*e#(rame333 ##########(inall?#1loop#repeat#to-write#do#1write-b?te# #o't33333 1de('n#read-(rame#1(rame-t?pe#in3 ##1handler-case#1read-val'e#(rame-t?pe#in3 ####1in-padding#13#nil333
&he ch#nge! #re in the c#ll! to read-(rame #nd write-val'e, 6here you need to p#!! the (rame-t?pe #rgu*ent #nd, in co*puting the !iAe o' the 'r#*e, 6here you need to u!e # 'unction (rame-header-si*e in!te#d o' the liter#l ?#lue 6 !ince the 'r#*e he#der ch#nged !iAe bet6een ?er!ion 2.2 #nd ?er!ion 2.3. Since the di''erence in the re!ult o' thi! 'unction i! b#!ed on the cl#!! o' the 'r#*e, it *#9e! !en!e to de'ine it #! # generic 'unction li9e thi!:
1de(generic#(rame-header-si*e#1(rame33
4ou@ll de'ine the nece!!#ry *ethod! on th#t generic 'unction in the ne.t !ection #'ter you de'ine the ne6 'r#*e cl#!!e!.
&he id3v!.3-(rame, on the other h#nd, reFuire! *ore ch#nge!. &he 'r#*e identi'ier #nd !iAe 'ield! 6ere e.tended in ?er!ion 2.3 'ro* three to 'our byte! e#ch, #nd t6o byte! 6orth o' 'l#g! 6ere #dded. %ddition#lly, the 'r#*e, li9e the ?er!ion 2.3 t#g, c#n cont#in option#l 'ield!, controlled by the ?#lue! o'
three o' the 'r#*e@! 'l#g!., With tho!e ch#nge! in *ind, you c#n de'ine the ?er!ion 2.3 'r#*e b#!e cl#!!, #long 6ith !o*e helper 'unction!, li9e thi!:
1de(ine-tagged-binar?-class#id3v!.3-(rame#13 ##11id################1(rame-id#:length#433 ###1si*e##############'43 ###1(lags#############'!3 ###1decompressed-si*e#1optional#:t?pe#C'4#:i(#1(rame-compressed-p#(lags333 ###1encr?ption-scheme#1optional#:t?pe#C'0#:i(#1(rame-encr?pted-p#(lags333 ###1gro'ping-identit?#1optional#:t?pe#C'0#:i(#1(rame-gro'ped-p#(lags3333 ##1:dispatch#1(ind-(rame-class#id333 1de('n#(rame-compressed-p#1(lags3#1logbitp#Q#(lags33 1de('n#(rame-encr?pted-p#1(lags3#1logbitp#6#(lags33 1de('n#(rame-gro'ped-p#1(lags3#1logbitp#"#(lags33
With the!e t6o cl#!!e! de'ined, you c#n no6 i*ple*ent the *ethod! on the generic 'unction (rameheader-si*e.
1de(method#(rame-header-si*e#11(rame#id3v!.!-(rame33#63 1de(method#(rame-header-si*e#11(rame#id3v!.3-(rame33#0 3
&he option#l 'ield! in # ?er!ion 2.3 'r#*e #ren@t counted #! p#rt o' the he#der 'or thi! co*put#tion !ince they@re #lre#dy included in the ?#lue o' the 'r#*e@! si*e.
>o6e?er, it@! # bit #nnoying th#t the!e t6o cl#!!e! #re the !#*e e.cept 'or their !upercl#!!. It@! not too b#d in thi! c#!e !ince there@! only one #ddition#l 'ield. 7ut i' you t#9e thi! #ppro#ch 'or other concrete 'r#*e cl#!!e!, one! th#t h#?e # *ore co*ple. intern#l !tructure th#t@! identic#l bet6een the t6o I+3 ?er!ion!, the duplic#tion 6ill be *ore ir9!o*e. %nother #ppro#ch, #nd the one you !hould #ctu#lly u!e, i! to de'ine # cl#!! generic-(rame #! # mi3in: # cl#!! intended to be u!ed #! # !upercl#!! #long 6ith one o' the ?er!ion-!peci'ic b#!e cl#!!e! to produce # concrete, ?er!ion-!peci'ic 'r#*e cl#!!. &he only tric9y bit #bout thi! #ppro#ch i! th#t i' generic-(rame doe!n@t e.tend either o' the 'r#*e b#!e cl#!!e!, then you c#n@t re'er to the si*e !lot in it! de'inition. In!te#d, you *u!t u!e the c'rrent-binar?-object 'unction I di!cu!!ed #t the end o' the pre?iou! ch#pter to #cce!! the ob<ect you@re in the *id!t o' re#ding or 6riting #nd p#!! it to si*e. %nd you need to #ccount 'or the di''erence in the nu*ber o' byte! o' the tot#l 'r#*e !iAe th#t 6ill be le't o?er, in the c#!e o' # ?er!ion 2.3 'r#*e, i' #ny o' the option#l 'ield! #re included in the
'r#*e. So, you !hould de'ine # generic 'unction data-b?tes 6ith *ethod! th#t do the right thing 'or both ?er!ion 2.2 #nd ?er!ion 2.3 'r#*e!.
1de(ine-binar?-class#generic-(rame#13 ##11data#1raw-b?tes#:si*e#1data-b?tes#1c'rrent-binar?-object333333 1de(generic#data-b?tes#1(rame33 1de(method#data-b?tes#11(rame#id3v!.!-(rame33 ##1si*e#(rame33 1de(method#data-b?tes#11(rame#id3v!.3-(rame33 ##1let#11(lags#1(lags#(rame333 ####1-#1si*e#(rame3 #######1i(#1(rame-compressed-p#(lags3#4# 3 #######1i(#1(rame-encr?pted-p#(lags3#0# 3 #######1i(#1(rame-gro'ped-p#(lags3#0# 3333
&hen you c#n de'ine concrete cl#!!e! th#t e.tend one o' the ?er!ion-!peci'ic b#!e cl#!!e! #nd generic-(rame to de'ine ?er!ion-!peci'ic generic 'r#*e cl#!!e!.
1de(ine-binar?-class#generic-(rame-v!.!#1id3v!.!-(rame#generic-(rame3#133 1de(ine-binar?-class#generic-(rame-v!.3#1id3v!.3-(rame#generic-(rame3#133
With the!e cl#!!e! de'ined, you c#n rede'ine the (ind-(rame-class 'unction to return the right ?er!ioned cl#!! b#!ed on the length o' the identi'ier.
1de('n#(ind-(rame-class#1id3 ##1ecase#1length#id3 ####13#Cgeneric-(rame-v!.!3 ####14#Cgeneric-(rame-v!.3333
Since you@ll 6#nt to pl#y 6ith thi! ob<ect # bit, you !hould !#?e it in # ?#ri#ble.
9<3K!/#1de(parameter#Uid3U#1read-id3#4/'sr!/mp3/Mit&a/Wintersongs/ !#L?la# $esta.mp3433
U9<3U
:o6 you c#n !ee, 'or e.#*ple, ho6 *#ny 'r#*e! it h#!.
9<3K!/#1length#1(rames#Uid3U33 00
59#y, th#t@! not too in'or*#ti?e. Wh#t you re#lly 6#nt to 9no6 #re 6h#t 9ind! o' 'r#*e! #re in there. In other 6ord!, you 6#nt to 9no6 the id! o' tho!e 'r#*e!, 6hich you c#n get 6ith # !i*ple MAPCAR li9e thi!:
9<3K!/#1mapcar#NCid#1(rames#Uid3U33 14FF!4#4FT04#4FIL4#4F.M4#4FTI4#4FH-4#4F$;4#4F-84#4$;%4#4$;%4#4$;%43
I' you loo9 up the!e identi'ier! in the I+3?2.2 !pec, you@ll di!co?er th#t #ll the 'r#*e! 6ith identi'ier! !t#rting 6ith T #re te.t in'or*#tion 'r#*e! #nd h#?e # !i*il#r !tructure. %nd COM i! the identi'ier 'or co**ent 'r#*e!, 6hich h#?e # !tructure !i*il#r to th#t o' te.t in'or*#tion 'r#*e!. &he p#rticul#r te.t in'or*#tion 'r#*e! identi'ied here turn out to be the 'r#*e! 'or repre!enting the !ong title, #rti!t, #lbu*, tr#c9, p#rt o' !et, ye#r, genre, #nd encoding progr#*. 5' cour!e, thi! i! <u!t one 3P3 'ile. 3#ybe other 'r#*e! #re u!ed in other 'ile!. It@! e#!y enough to di!co?er. /ir!t de'ine # 'unction th#t co*bine! the pre?iou! MAPCAR e.pre!!ion 6ith # c#ll to readid3 #nd 6r#p! the 6hole thing in # DELETE-DUPLICATES to 9eep thing! tidy. 4ou@ll h#?e to u!e # :test #rgu*ent o' NCstring= to DELETE-DUPLICATES to !peci'y th#t you 6#nt t6o ele*ent! con!idered the !#*e i' they@re the !#*e !tring.
1de('n#(rame-t?pes#1(ile3 ##1delete-d'plicates#1mapcar#NCid#1(rames#1read-id3#(ile333#:test#NCstring=33
&hi! !hould gi?e the !#*e #n!6er e.cept 6ith only one o' e#ch identi'ier 6hen p#!!ed the !#*e 'ilen#*e.
9<3K!/#1(rame-t?pes#4/'sr!/mp3/Mit&a/Wintersongs/ !#L?la#$esta.mp343 14FF!4#4FT04#4FIL4#4F.M4#4FTI4#4FH-4#4F$;4#4F-84#4$;%43
&hen you c#n u!e Ch#pter 15@! wal&-director? 'unction #long 6ith mp3-p to 'ind e?ery 3P3 'ile under # directory #nd co*bine the re!ult! o' c#lling (rame-t?pes on e#ch 'ile. $ec#ll th#t NUNION i! the recycling ?er!ion o' the UNION 'unctionG !ince (rame-t?pes *#9e! # ne6 li!t 'or e#ch 'ile, thi! i! !#'e.
1de('n#(rame-t?pes-in-dir#1dir3 ##1let#11ids#1333 ####1(let#11collect#1(ile3 #############1set(#ids#1n'nion#ids#1(rame-t?pes#(ile3#:test#NCstring=3333 ######1wal&-director?#dir#NCcollect#:test#NCmp3-p33 ####ids33
:o6 p#!! it the n#*e o' # directory, #nd it@ll tell you the !et o' identi'ier! u!ed in #ll the 3P3 'ile! under th#t directory. It *#y t#9e # 'e6 !econd! depending ho6 *#ny 3P3 'ile! you h#?e, but you@ll prob#bly get !o*ething !i*il#r to thi!:
9<3K!/#1(rame-t?pes-in-dir#4/'sr!/mp3/43 14F$;84#4$;%%4#4F.$M4#4F9F!4#4FT-04#4FILL4#4F$T4#4FF!4#4FT04#4F$%4 #4FIL4#4F.M4#4FTI4#4FH-4#4F$;4#4F-84#4$;%43
&he 'our-letter identi'ier! #re the ?er!ion 2.3 eFui?#lent! o' the ?er!ion 2.2 identi'ier! I di!cu!!ed pre?iou!ly. Since the in'or*#tion !tored in tho!e 'r#*e! i! e.#ctly the in'or*#tion you@ll need in Ch#pter 22, it *#9e! !en!e to i*ple*ent cl#!!e! only 'or the 'r#*e! #ctu#lly u!ed, n#*ely, te.t in'or*#tion #nd co**ent 'r#*e!, 6hich you@ll do in the ne.t t6o !ection!. I' you decide l#ter th#t you 6#nt to !upport other 'r#*e type!, it@! *o!tly # *#tter o' tr#n!l#ting the I+3 !peci'ic#tion! into the #ppropri#te bin#ry cl#!! de'inition!.
&hen string-args u!e! the encoding byte, the length, #nd the ter*in#tor to deter*ine !e?er#l o' the #rgu*ent! to be p#!!ed to read-val'e #nd write-val'e by the :reader #nd :writer o' id3-encoded-string. 5ne o' the length #nd ter*in#tor #rgu*ent! to string-args !hould #l6#y! be NIL.
1de('n#string-args#1encoding#length#terminator3 ##1cond# ####1length #####1val'es#1non-terminated-t?pe#encoding3#:length#length33 ####1terminator #####1val'es#1terminated-t?pe#encoding3#:terminator#terminator3333
With tho!e helper!, the de'inition o' id3-encoded-string i! !i*ple. 5ne det#il to note i! th#t the 9ey6ord--either :length or :terminator--u!ed in the c#ll to read-val'e #nd write-val'e# i! <u!t #nother piece o' d#t# returned by string-args. %lthough 9ey6ord! in #rgu*ent! li!t! #re #l*o!t #l6#y! liter#l 9ey6ord!, they don@t h#?e to be.
1de(ine-binar?-t?pe#id3-encoded-string#1encoding#length#terminator3 ##1:reader#1in3# ####1m'ltiple-val'e-bind#1t?pe#&e?word#arg3 ########1string-args#encoding#length#terminator3 ######1read-val'e#t?pe#in#&e?word#arg333 ##1:writer#1o't#string3 ####1m'ltiple-val'e-bind#1t?pe#&e?word#arg3 ########1string-args#encoding#length#terminator3 ######1write-val'e#t?pe#o't#string#&e?word#arg3333
:o6 you c#n de'ine # te)t-in(o *i.in cl#!!, *uch the 6#y you de'ined generic-(rame e#rlier.
1de(ine-binar?-class#te)t-in(o-(rame#13 ##11encoding#'03 ###1in(ormation#1id3-encoded-string#:encoding#encoding#:length#1b?tes-le(t#033333
%! 6hen you de'ined generic-(rame, you need #cce!! to the !iAe o' the 'r#*e, in thi! c#!e to co*pute the :length #rgu*ent to p#!! to id3-encoded-string. 7ec#u!e you@ll need to do # !i*il#r co*put#tion in the ne.t cl#!! you de'ine, you c#n go #he#d #nd de'ine # helper 'unction, b?tes-le(t, th#t u!e! c'rrent-binar?-object to get #t the !iAe o' the 'r#*e.
1de('n#b?tes-le(t#1b?tes-read3 ##1-#1si*e#1c'rrent-binar?-object33#b?tes-read33
:o6, #! you did 6ith the generic-(rame *i.in, you c#n de'ine t6o ?er!ion-!peci'ic concrete cl#!!e! 6ith # *ini*u* o' duplic#ted code.
1de(ine-binar?-class#te)t-in(o-(rame-v!.!#1id3v!.!-(rame#te)t-in(o-(rame3#133 1de(ine-binar?-class#te)t-in(o-(rame-v!.3#1id3v!.3-(rame#te)t-in(o-(rame3#133
&o 6ire the!e cl#!!e! in, you need to *odi'y (ind-(rame-class to return the #ppropri#te cl#!! n#*e 6hen the I+ indic#te! the 'r#*e i! # te.t in'or*#tion 'r#*e, n#*ely, 6hene?er the I+ !t#rt! 6ith T #nd i!n@t TAA or TAAA.
1de('n#(ind-(rame-class#1name3 ##1cond ####11and#1char=#1char#name# 3#NYF3 ##########1not#1member#name#C14F[[4#4F[[[43#:test#NCstring=333 #####1ecase#1length#name3 #######13#Cte)t-in(o-(rame-v!.!3 #######14#Cte)t-in(o-(rame-v!.3333 ####1t #####1ecase#1length#name3 #######13#Cgeneric-(rame-v!.!3 #######14#Cgeneric-(rame-v!.333333
#o$$ent Fra$es
%nother co**only u!ed 'r#*e type i! the co**ent 'r#*e, 6hich i! li9e # te.t in'or*#tion 'r#*e 6ith
# 'e6 e.tr# 'ield!. i9e # te.t in'or*#tion 'r#*e, it !t#rt! 6ith # !ingle byte indic#ting the !tring encoding u!ed in the 'r#*e. &h#t byte i! 'ollo6ed by # three-ch#r#cter IS5 ,,5)-1 !tring Breg#rdle!! o' the ?#lue o' the !tring encoding byteC, 6hich indic#te! 6h#t l#ngu#ge the co**ent i! in u!ing #n IS503)-2 code, 'or e.#*ple, HengH 'or (ngli!h or H<pnH 'or D#p#ne!e. &h#t 'ield i! 'ollo6ed by t6o !tring! encoded #! indic#ted by the 'ir!t byte. &he 'ir!t i! # null-ter*in#ted !tring cont#ining # de!cription o' the co**ent. &he !econd, 6hich t#9e! up the re*#inder o' the 'r#*e, i! the co**ent te.t it!el'.
1de(ine-binar?-class#comment-(rame#13 ##11encoding#'03 ###1lang'age#1iso-RR"9-0-string#:length#333 ###1description#1id3-encoded-string#:encoding#encoding#:terminator#2n'll233 ###1te)t#1id3-encoded-string ##########:encoding#encoding ##########:length#1b?tes-le(t ###################12#0#S#encoding ######################3#S#lang'age ######################1encoded-string-length#description#encoding#t3333333
%! in the de'inition o' the te)t-in(o *i.in, you c#n u!e b?tes-le(t to co*pute the !iAe o' the 'in#l !tring. >o6e?er, !ince the description 'ield i! # ?#ri#ble-length !tring, the nu*ber o' byte! re#d prior to the !t#rt o' te)t i!n@t # con!t#nt. &o *#9e *#tter! 6or!e, the nu*ber o' byte! u!ed to encode description i! dependent on the encoding. So, you !hould de'ine # helper 'unction th#t return! the nu*ber o' byte! u!ed to encode # !tring gi?en the !tring, the encoding code, #nd # boole#n indic#ting 6hether the !tring i! ter*in#ted 6ith #n e.tr# ch#r#cter.
1de('n#encoded-string-length#1string#encoding#terminated3 ##1let#11characters#12#1length#string3#1i(#terminated#0# 3333 ####1U#characters#1ecase#encoding#1 #03#10#!33333
%nd, #! be'ore, you c#n de'ine the concrete ?er!ion-!peci'ic co**ent 'r#*e cl#!!e! #nd 6ire the* into (ind-(rame-class.
1de(ine-binar?-class#comment-(rame-v!.!#1id3v!.!-(rame#comment-(rame3#133 1de(ine-binar?-class#comment-(rame-v!.3#1id3v!.3-(rame#comment-(rame3#133 1de('n#(ind-(rame-class#1name3 ##1cond ####11and#1char=#1char#name# 3#NYF3 ##########1not#1member#name#C14F[[4#4F[[[43#:test#NCstring=333 #####1ecase#1length#name3 #######13#Cte)t-in(o-(rame-v!.!3 #######14#Cte)t-in(o-(rame-v!.3333 ####11string=#name#4$;%43##Ccomment-(rame-v!.!3 ####11string=#name#4$;%%43#Ccomment-(rame-v!.33 ####1t #####1ecase#1length#name3 #######13#Cgeneric-(rame-v!.!3 #######14#Cgeneric-(rame-v!.333333
cl#!!e! 'or #ll the 'r#*e type!. 4ou@d #l!o need to de'ine *ethod! 'or *#nipul#ting the t#g #nd 'r#*e ob<ect! in # con!i!tent 6#y B'or in!t#nce, i' you ch#nge the ?#lue o' # !tring in # te)t-in(o-(rame, you@ll li9ely need to #d<u!t the !iAeCG #! the code !t#nd!, there@! nothing to *#9e !ure th#t h#ppen!.) 5r, i' you <u!t need to e.tr#ct cert#in piece! o' in'or*#tion #bout #n 3P3 'ile 'ro* it! I+3 t#g--#! you 6ill 6hen you de?elop # !tre#*ing 3P3 !er?er in Ch#pter! 22, 2,, #nd 2)--you@ll need to 6rite 'unction! th#t 'ind the #ppropri#te 'r#*e! #nd e.tr#ct the in'or*#tion you 6#nt. /in#lly, to *#9e thi! production-Fu#lity code, you@d h#?e to pore o?er the I+3 !pec! #nd de#l 6ith the det#il! I !9ipped o?er in the intere!t o' !p#ce. In p#rticul#r, !o*e o' the 'l#g! in both the t#g #nd the 'r#*e c#n #''ect the 6#y the content! o' the t#g or 'r#*e i! re#dG unle!! you 6rite !o*e code th#t doe! the right thing 6hen tho!e 'l#g! #re !et, there *#y be I+3 t#g! th#t thi! code 6on@t be #ble to p#r!e correctly. 7ut the code 'ro* thi! ch#pter !hould be c#p#ble o' p#r!ing ne#rly #ll the 3P3! you #ctu#lly encounter. /or no6 you c#n 'ini!h 6ith # 'e6 'unction! to e.tr#ct indi?idu#l piece! o' in'or*#tion 'ro* #n id3tag. 4ou@ll need the!e 'unction! in Ch#pter 22 #nd prob#bly in other code th#t u!e! thi! libr#ry. &hey belong in thi! libr#ry bec#u!e they depend on det#il! o' the I+3 'or*#t th#t the u!er! o' thi! libr#ry !houldn@t h#?e to 6orry #bout. &o get, !#y, the n#*e o' the !ong o' the 3P3 'ro* 6hich #n id3-tag 6#! e.tr#cted, you need to 'ind the I+3 'r#*e 6ith # !peci'ic identi'ier #nd then e.tr#ct the in'or*#tion 'ield. %nd !o*e piece! o' in'or*#tion, !uch #! the genre, c#n reFuire 'urther decoding. uc9ily, #ll the 'r#*e! th#t cont#in the in'or*#tion you@ll c#re #bout #re te.t in'or*#tion 'r#*e!, !o e.tr#cting # p#rticul#r piece o' in'or*#tion *o!tly boil! do6n to u!ing the right identi'ier to loo9 up the #ppropri#te 'r#*e. 5' cour!e, the I+3 #uthor! decided to ch#nge #ll the identi'ier! bet6een I+3?2.2 #nd I+3?2.3, !o you@ll h#?e to #ccount 'or th#t. :othing too co*ple.--you <u!t need to 'igure out the right p#th to get to the ?#riou! piece! o' in'or*#tion. &hi! i! # per'ect bit o' code to de?elop inter#cti?ely, *uch the 6#y you 'igured out 6h#t 'r#*e cl#!!e! you needed to i*ple*ent. &o !t#rt, you need #n id3-tag ob<ect to pl#y 6ith. %!!u*ing you h#?e #n 3P3 l#ying #round, you c#n u!e read-id3 li9e thi!:
9<3K!/#1de(parameter#Uid3U#1read-id3#4Mit&a/Wintersongs/ !#L?la#$esta.mp3433 U9<3U 9<3K!/#Uid3U NO9<3K!.!-FIJ#P#N)Q3d 4c0a/
repl#cing Mit&a/Wintersongs/ !#L?la#$esta.mp3 6ith the 'ilen#*e o' your 3P3. 5nce you h#?e your id3-tag ob<ect, you c#n !t#rt po9ing #round. /or in!t#nce, you c#n chec9 out the li!t o' 'r#*e ob<ect! 6ith the (rames 'unction.
9<3K!/#1(rames#Uid3U3 1NOF-[F-98E;-E.I%--K!.!#P#N)Q3d 4cca/ #NOF-[F-98E;-E.I%--K!.!#P#N)Q3d 4dba/ #NOF-[F-98E;-E.I%--K!.!#P#N)Q3d 4ea!/ #NOF-[F-98E;-E.I%--K!.!#P#N)Q3d 4(9a/ #NOF-[F-98E;-E.I%--K!.!#P#N)Q3d " R!/ #NOF-[F-98E;-E.I%--K!.!#P#N)Q3d "06a/ #NOF-[F-98E;-E.I%--K!.!#P#N)Q3d "!"!/ #NOF-[F-98E;-E.I%--K!.!#P#N)Q3d "33a/ #NO$;%%-8F-E.I%--K!.!#P#N)Q3d "43a/ #NO$;%%-8F-E.I%--K!.!#P#N)Q3d "60!/ #NO$;%%-8F-E.I%--K!.!#P#N)Q3d "R6a/3
:o6 !uppo!e you 6#nt to e.tr#ct the !ong title. It@! prob#bly in one o' tho!e 'r#*e!, but to 'ind it, you need to 'ind the 'r#*e 6ith the H&&2H identi'ier. Well, you c#n chec9 e#!ily enough to !ee i' the t#g cont#in! !uch # 'r#*e by e.tr#cting #ll the identi'ier! li9e thi!:
9<3K!/#1mapcar#NCid#1(rames#Uid3U33 14FF!4#4FT04#4FIL4#4F.M4#4FTI4#4FH-4#4F$;4#4F-84#4$;%4#4$;%4#4$;%43
&here it i!, the 'ir!t 'r#*e. >o6e?er, there@! no gu#r#ntee it@ll #l6#y! be the 'ir!t 'r#*e, !o you !hould prob#bly loo9 it up by identi'ier r#ther th#n po!ition. &h#t@! #l!o !tr#ight'or6#rd u!ing the FIND 'unction.
9<3K!/#1(ind#4FF!4#1(rames#Uid3U3#:test#NCstring=#:&e?#NCid3 NOF-[F-98E;-E.I%--K!.!#P#N)Q3d 4cca/
Whoop!. &h#t `P i! ho6 (*#c! print! # null ch#r#cter. In # *#neu?er re*ini!cent o' the 9ludge th#t turned I+3?1 into I+3?1.1, the in(ormation !lot o' # te.t in'or*#tion 'r#*e, though not o''ici#lly # null-ter*in#ted !tring, c#n cont#in # null, #nd I+3 re#der! #re !uppo!ed to ignore #ny ch#r#cter! #'ter the null. So, you need # 'unction th#t t#9e! # !tring #nd return! the content! up to the 'ir!t null ch#r#cter, i' #ny. &h#t@! e#!y enough u!ing the 2n'll2 con!t#nt 'ro* the bin#ry d#t# libr#ry.
1de('n#'pto-n'll#1string3 ##1s'bse@#string# #1position#2n'll2#string333
4ou could <u!t 6r#p th#t code in # 'unction n#*ed song th#t t#9e! #n id3-tag #! #n #rgu*ent, #nd you@d be done. >o6e?er, the only di''erence bet6een thi! code #nd the code you@ll u!e to e.tr#ct the other piece! o' in'or*#tion you@ll need B!uch #! the #lbu* n#*e, the #rti!t, #nd the genreC i! the identi'ier. So, it@! better to !plit up the code # bit. /or !t#rter!, you c#n 6rite # 'unction th#t <u!t 'ind! # 'r#*e gi?en #n id3-tag #nd #n identi'ier li9e thi!:
1de('n#(ind-(rame#1id3#id3 ##1(ind#id#1(rames#id33#:test#NCstring=#:&e?#NCid33 9<3K!/#1(ind-(rame#Uid3U#4FF!43 NOF-[F-98E;-E.I%--K!.!#P#N)Q3d 4cca/
&hen the other bit o' code, the p#rt th#t e.tr#ct! the in'or*#tion 'ro* # te)t-in(o-(rame, c#n go in #nother 'unction.
1de('n#get-te)t-in(o#1id3#id3 ##1let#11(rame#1(ind-(rame#id3#id333 ####1when#(rame#1'pto-n'll#1in(ormation#(rame33333 9<3K!/#1get-te)t-in(o#Uid3U#4FF!43 4L?la#$esta4
:o6 the de'inition o' song i! <u!t # *#tter o' p#!!ing the right identi'ier.
1de('n#song#1id33#1get-te)t-in(o#id3#4FF!433 9<3K!/#1song#Uid3U3 4L?la#$esta4
>o6e?er, thi! de'inition o' song 6or9! only 6ith ?er!ion 2.2 t#g! !ince the identi'ier ch#nged 'ro* H&&2H to H&I&2H bet6een ?er!ion 2.2 #nd ?er!ion 2.3. %nd #ll the other t#g! ch#nged too. Since the u!er o' thi! libr#ry !houldn@t h#?e to 9no6 #bout di''erent ?er!ion! o' the I+3 'or*#t to do !o*ething #! !i*ple #! get the !ong title, you !hould prob#bly h#ndle tho!e det#il! 'or the*. % !i*ple 6#y i! to ch#nge (ind-(rame to t#9e not <u!t # !ingle identi'ier but # li!t o' identi'ier! li9e thi!:
1de('n#(ind-(rame#1id3#ids3 ##1(ind-i(#NC1lambda#1)3#1(ind#1id#)3#ids#:test#NCstring=33#1(rames#id3333
&hen ch#nge get-te)t-in(o !lightly !o it c#n t#9e one or *ore identi'ier! u!ing # &&'(! p#r#*eter.
1de('n#get-te)t-in(o#1id3#>rest#ids3 ##1let#11(rame#1(ind-(rame#id3#ids333 ####1when#(rame#1'pto-n'll#1in(ormation#(rame33333
&hen the ch#nge needed to #llo6 song to !upport both ?er!ion 2.2 #nd ?er!ion 2.3 t#g! i! <u!t # *#tter o' #dding the ?er!ion 2.3 identi'ier.
1de('n#song#1id33#1get-te)t-in(o#id3#4FF!4#4F9F!433
&hen you <u!t need to loo9 up the #ppropri#te ?er!ion 2.2 #nd ?er!ion 2.3 'r#*e identi'ier! 'or #ny 'ield! 'or 6hich you 6#nt to pro?ide #n #cce!!or 'unction. >ere #re the one! you@ll need in Ch#pter 22:
1de('n#alb'm#1id33#1get-te)t-in(o#id3#4FIL4#4FILL433 1de('n#artist#1id33#1get-te)t-in(o#id3#4FT04#4FT-0433 1de('n#tracid33#1get-te)t-in(o#id3#4F.M4#4F.$M433 1de('n#?ear#1id33#1get-te)t-in(o#id3#4FH-4#4FH-.4#4F<.$433 1de('n#genre#1id33#1get-te)t-in(o#id3#4F$;4#4F$;8433
&he l#!t 6rin9le i! th#t the 6#y the genre i! !tored in the &C5 or &C5: 'r#*e! i!n@t #l6#y! hu*#n re#d#ble. $ec#ll th#t in I+3?1, genre! 6ere !tored #! # !ingle byte th#t encoded # p#rticul#r genre 'ro* # 'i.ed li!t. 8n'ortun#tely, tho!e code! li?e on in I+3?2--i' the te.t o' the genre 'r#*e i! # nu*ber in p#renthe!e!, the nu*ber i! !uppo!ed to be interpreted #! #n I+3?1 genre code. 7ut, #g#in, u!er! o' thi! libr#ry prob#bly 6on@t c#re #bout th#t #ncient hi!tory. So, you !hould pro?ide # 'unction th#t #uto*#tic#lly tr#n!l#te! the genre. &he 'ollo6ing 'unction u!e! the genre 'unction <u!t de'ined to e.tr#ct the #ctu#l genre te.t #nd then chec9! 6hether it !t#rt! 6ith # le't p#renthe!i!, decoding the ?er!ion 1 genre code 6ith # 'unction you@ll de'ine in # *o*ent i' it doe!:
1de('n#translated-genre#1id33 ##1let#11genre#1genre#id3333 ####1i(#1and#genre#1char=#NY1#1char#genre# 333 ######1translate-v0-genre#genre3 ######genre333
Since # ?er!ion 1 genre code i! e''ecti?ely <u!t #n inde. into #n #rr#y o' !t#nd#rd n#*e!, the e#!ie!t 6#y to i*ple*ent translate-v0-genre i! to e.tr#ct the nu*ber 'ro* the genre !tring #nd u!e it #! #n inde. into #n #ctu#l #rr#y.
1de('n#translate-v0-genre#1genre3 ##1are(#Uid3-v0-genresU#1parse-integer#genre#:start#0#:j'n&-allowed#t333
&hen #ll you need to do i! to de'ine the #rr#y o' n#*e!. &he 'ollo6ing #rr#y o' n#*e! include! the ,0 o''ici#l ?er!ion 1 genre! plu! the genre! cre#ted by the #uthor! o' Win#*p:
1de(parameter#Uid3-v0-genresU ##N1 ####SS#Fhese#are#the#o((icial#9<3v0#genres. ####4Ll'es4#4$lassic#.oc&4#4$o'ntr?4#4<ance4#4<isco4#4E'n&4#4Jr'nge4 ####4:ip-:op4#4_a**4#4%etal4#48ew#Ige4#4;ldies4#4;ther4#4Top4#4.>L4#4.ap4 ####4.eggae4#4.oc&4#4Fechno4#49nd'strial4#4Ilternative4#4,&a4 ####4<eath#%etal4#4Tran&s4#4,o'ndtrac&4#4-'ro-Fechno4#4Imbient4 ####4Frip-:op4#4Kocal4#4_a**2E'n&4#4E'sion4#4France4#4$lassical4 ####49nstr'mental4#4Icid4#4:o'se4#4Jame4#4,o'nd#$lip4#4Jospel4#48oise4 ####4Iltern.oc&4#4Lass4#4,o'l4#4T'n&4#4,pace4#4%editative4 ####49nstr'mental#Top4#49nstr'mental#.oc&4#4-thnic4#4Jothic4#4<ar&wave4 ####4Fechno-9nd'strial4#4-lectronic4#4Top-Eol&4#4-'rodance4#4<ream4 ####4,o'thern#.oc&4#4$omed?4#4$'lt4#4Jangsta4#4Fop#4 4#4$hristian#.ap4 ####4Top/E'n&4#4_'ngle4#48ative#Imerican4#4$abaret4#48ew#Wave4 ####4Ts?chadelic4#4.ave4#4,howt'nes4#4Frailer4#4Lo-Ei4#4Fribal4 ####4Icid#T'n&4#4Icid#_a**4#4Tol&a4#4.etro4#4%'sical4#4.oc&#>#.oll4 ####4:ard#.oc&4 ####SS#Fhese#were#made#'p#b?#the#a'thors#o(#Winamp#b't#bac&ported#into ####SS#the#9<3#spec. ####4Eol&4#4Eol&-.oc&4#48ational#Eol&4#4,wing4#4East#E'sion4 ####4Lebob4#4Latin4#4.evival4#4$eltic4#4Ll'egrass4#4Ivantgarde4 ####4Jothic#.oc&4#4Trogressive#.oc&4#4Ts?chedelic#.oc&4#4,?mphonic#.oc&4 ####4,low#.oc&4#4Lig#Land4#4$hor's4#4-as?#Listening4#4Ico'stic4#4:'mo'r4 ####4,peech4#4$hanson4#4;pera4#4$hamber#%'sic4#4,onata4#4,?mphon?4 ####4Loot?#Lass4#4Trim's4#4Torn#Jroove4#4,atire4#4,low#_am4#4$l'b4 ####4Fango4#4,amba4#4Eol&lore4#4Lallad4#4Tower#Lallad4#4.h?thmic#,o'l4 ####4Ereest?le4#4<'et4#4T'n&#.oc&4#4<r'm#,olo4#4I#capella4#4-'ro-:o'se4 ####4<ance#:all4 ####SS#Fhese#were#also#invented#b?#the#Winamp#(ol&s#b't#ignored#b?#the ####SS#9<3#a'thors. ####4Joa4#4<r'm#>#Lass4#4$l'b-:o'se4#4:ardcore4#4Ferror4#49ndie4 ####4LritTop4#48egerp'n&4#4Tols&#T'n&4#4Leat4#4$hristian#Jangsta#.ap4 ####4:eav?#%etal4#4Llac&#%etal4#4$rossover4#4$ontemporar?#$hristian4 ####4$hristian#.oc&4#4%ereng'e4#4,alsa4#4Fhrash#%etal4#4Inime4#4_pop4 ####4,?nthpop433
5nce #g#in, it prob#bly 'eel! li9e you 6rote # ton o' code in thi! ch#pter. 7ut i' you put it #ll in # 'ile, or i' you do6nlo#d the ?er!ion 'ro* thi! boo9@! Web !ite, you@ll !ee it@! <u!t not th#t *#ny line!--*o!t o' the p#in o' 6riting thi! libr#ry !te*! 'ro* h#?ing to under!t#nd the intric#cie! o' the I+3 'or*#t it!el'. %ny6#y, no6 you h#?e # *#<or piece o' 6h#t you@ll turn into # !tre#*ing 3P3 !er?er in Ch#pter! 22, 2,, #nd 2). &he other *#<or bit o' in'r#!tructure you@ll need i! # 6#y to 6rite !er?er-!ide Web !o't6#re, the topic o' the ne.t ch#pter.
1*ipping
i! the proce!! by 6hich # !ong on #n #udio C+ i! con?erted to #n 3P3 'ile on your h#rd dri?e. &he!e d#y! *o!t ripping !o't6#re #l!o #uto*#tic#lly retrie?e! in'or*#tion #bout the !ong! being ripped 'ro* online d#t#b#!e! !uch #! =r#cenote Bn^e the Co*p#ct +i!c +#t#b#!e JC++7KC or /ree+7, 6hich it then e*bed! in the 3P3 'ile! #! I+3 t#g!.
2%l*o!t
#ll 'ile !y!te*! pro?ide the #bility to o?er6rite e.i!ting byte! o' # 'ile, but 'e6, i' #ny, pro?ide # 6#y to #dd or re*o?e d#t# #t the beginning or *iddle o' # 'ile 6ithout h#?ing to re6rite the re!t o' the 'ile. Since I+3 t#g! #re typic#lly !tored #t the beginning o' # 'ile, to re6rite #n I+3 t#g 6ithout di!turbing the re!t o' the 'ile you *u!t repl#ce the old t#g 6ith # ne6 t#g o' e.#ctly the !#*e length. 7y 6riting I+3 t#g! 6ith # cert#in #*ount o' p#dding, you h#?e # better ch#nce o' being #ble to do !o--i' the ne6 t#g h#! *ore d#t# th#n the origin#l t#g, you u!e le!! p#dding, #nd i' it@! !horter, you u!e *ore.
3&he
'r#*e d#t# 'ollo6ing the I+3 he#der could #l!o potenti#lly cont#in the illeg#l !eFuence. &h#t@! pre?ented u!ing # di''erent !che*e th#t@! turned on ?i# one o' the 'l#g! in the t#g he#der. &he code in thi! ch#pter doe!n@t #ccount 'or the po!!ibility th#t thi! 'l#g *ight be !etG in pr#ctice it@! r#rely u!ed.
-In
I+3?2.-, 8CS-2 i! repl#ced by the ?irtu#lly identic#l 8&/-10, #nd 8&/-107( #nd 8&/-, #re #dded #! #ddition#l encoding!.
5&he
2.- ?er!ion o' the I+3 'or*#t #l!o !upport! pl#cing # 'ooter #t the end o' # t#g, 6hich *#9e! it e#!ier to 'ind # t#g #ppended to the end o' # 'ile.
0Ch#r#cter 2I'
!tre#*! !upport t6o 'unction!, PEE+-CHAR #nd UNREAD-CHAR, either o' 6hich 6ould be # per'ect !olution to thi! proble*, but bin#ry !tre#*! !upport no eFui?#lent 'unction!. # t#g h#d #n e.tended he#der, you could u!e thi! ?#lue to deter*ine 6here the 'r#*e d#t# !hould end. >o6e?er, i' the e.tended he#der i!n@t u!ed, you@d h#?e to u!e the old #lgorith* #ny6#y, !o it@! not 6orth #dding code to do it #nother 6#y.
,&he!e
'l#g!, in #ddition to controlling 6hether the option#l 'ield! #re included, c#n #''ect the p#r!ing o' the re!t o' the t#g. In p#rticul#r, i' the !e?enth bit o' the 'l#g! i! !et, then the #ctu#l 'r#*e d#t# i! co*pre!!ed u!ing the Alib #lgorith*, #nd i' the !i.th bit i! !et, the d#t# i! encrypted. In pr#ctice the!e option! #re r#rely, i' e?er, u!ed, !o you c#n get #6#y 6ith ignoring the* 'or no6. 7ut th#t 6ould be #n #re# you@d h#?e to #ddre!! to *#9e thi! # production-Fu#lity I+3 libr#ry. 5ne !i*ple h#l' !olution 6ould be to ch#nge (ind-(rame-class to #ccept # !econd #rgu*ent #nd p#!! it the 'l#g!G i' the 'r#*e i! co*pre!!ed or encrypted, you could in!t#nti#te # generic 'r#*e to hold the d#t#.
)(n!uring
th#t 9ind o' inter'ield con!i!tency 6ould be # 'ine #pplic#tion 'or :a(ter *ethod! on the #cce!!or generic 'unction!. /or in!t#nce, you could de'ine thi! :a(ter *ethod to 9eep si*e in !ync 6ith the in(ormation !tring:
1de(method#1set(#in(ormation3#:a(ter#1val'e#1(rame#te)t-in(o-(rame33 ##1declare#1ignore#val'e33 ##1with-slots#1encoding#si*e#in(ormation3#(rame ####1set(#si*e#1encoded-string-length#in(ormation#encoding#nil3333
/igure 20-1. S#*ple Web p#ge &he bro6!er #nd !er?er co**unic#te u!ing # protocol c#lled the >yperte.t &r#n!'er Protocol B>&&PC.
While you don@t need to 6orry #bout the det#il! o' the protocol, it@! 6orth under!t#nding th#t it con!i!t! entirely o' # !eFuence o' reFue!t! initi#ted by the bro6!er #nd re!pon!e! gener#ted by the !er?er. &h#t i!, the bro6!er connect! to the Web !er?er #nd !end! # reFue!t th#t include!, #t the le#!t, the de!ired 8$ #nd the ?er!ion o' >&&P th#t the bro6!er !pe#9!. &he bro6!er c#n #l!o include d#t# in it! reFue!tG th#t@! ho6 the bro6!er !ub*it! >&3 'or*! to the !er?er. &o reply to # reFue!t, the !er?er !end! # re!pon!e *#de up o' # !et o' he#der! #nd # body. &he he#der! cont#in in'or*#tion #bout the body, !uch #! 6h#t type o' d#t# it i! B'or in!t#nce, >&3 , pl#in te.t, or #n i*#geC, #nd the body i! the d#t# it!el', 6hich i! then rendered by the bro6!er. &he !er?er c#n #l!o !end #n error re!pon!e telling the bro6!er th#t it! reFue!t couldn@t be #n!6ered 'or !o*e re#!on. %nd th#t@! pretty *uch it. 5nce the bro6!er h#! recei?ed the co*plete re!pon!e 'ro* the !er?er, there@! no co**unic#tion bet6een the bro6!er #nd the !er?er until the ne.t ti*e the bro6!er decide! to reFue!t # p#ge 'ro* the !er?er.2 &hi! i! the *#in con!tr#int o' Web progr#**ing--there@! no 6#y 'or code running on the !er?er to #''ect 6h#t the u!er !ee! in their bro6!er unle!! the bro6!er i!!ue! # ne6 reFue!t to the !er?er.3 So*e Web p#ge!, c#lled static p#ge!, #re !i*ply >&3 'ile! !tored on the Web !er?er #nd !er?ed up 6hen reFue!ted by the bro6!er. D0namic p#ge!, on the other h#nd, con!i!t o' >&3 gener#ted e#ch ti*e the p#ge i! reFue!ted by # bro6!er. /or in!t#nce, # dyn#*ic p#ge *ight be gener#ted by Fuerying # d#t#b#!e #nd then con!tructing >&3 to repre!ent the re!ult! o' the Fuery.When gener#ting it! re!pon!e to # reFue!t, !er?er-!ide code h#! 'our *#in piece! o' in'or*#tion to #ct on. &he 'ir!t piece o' in'or*#tion i! the reFue!ted 8$ . &ypic#lly, ho6e?er, the 8$ i! u!ed by the Web !er?er it!el' to deter*ine what code i! re!pon!ible 'or gener#ting the re!pon!e. :e.t, i' the 8$ cont#in! # Fue!tion *#r9, e?erything #'ter the Fue!tion *#r9 i! con!idered to be # 4uer0 string, 6hich i! typic#lly ignored by the Web !er?er e.cept th#t it *#9e! it #?#il#ble to the code gener#ting the re!pon!e. 3o!t o' the ti*e the Fuery !tring cont#in! # !et o' 9ey;?#lue p#ir!. &he reFue!t 'ro* the bro6!er c#n #l!o cont#in post data, 6hich #l!o u!u#lly con!i!t! o' 9ey;?#lue p#ir!. Po!t d#t# i! typic#lly u!ed to !ub*it >&3 'or*!. &he 9ey;?#lue p#ir! !upplied in either the Fuery !tring or the po!t d#t# #re collecti?ely c#lled the 4uer0 parameters. /in#lly, in order to !tring together # !eFuence o' indi?idu#l reFue!t! 'ro* the !#*e bro6!er, code running in the !er?er c#n set a coo$ie, !ending # !peci#l he#der in it! re!pon!e to the bro6!er th#t cont#in! # bit o' op#Fue d#t# c#lled # coo$ie. %'ter # coo9ie i! !et by # p#rticul#r !er?er, the bro6!er 6ill !end the coo9ie 6ith e#ch reFue!t it !end! to th#t !er?er. &he bro6!er doe!n@t c#re #bout the d#t# in the coo9ie--it <u!t echoe! it b#c9 to the !er?er 'or the !er?er-!ide code to interpret ho6e?er it 6#nt!. &he!e #re the pri*iti?e ele*ent! on top o' 6hich )) percent o' !er?er-!ide Web progr#**ing i! built. &he bro6!er !end! # reFue!t, the !er?er 'ind! !o*e code to h#ndle the reFue!t #nd run! it, #nd the code u!e! Fuery p#r#*eter! #nd coo9ie! to deter*ine 6h#t to do.
A%%egro/er,e
4ou c#n !er?e Web content u!ing Co**on i!p in # nu*ber o' 6#y!G there #re #t le#!t three open!ource Web !er?er! 6ritten in Co**on i!p #! 6ell #! plug-in! !uch #! *od_li!p5 #nd i!plet!0 th#t #llo6 the %p#che Web !er?er or #ny D#?# Ser?let cont#iner to deleg#te reFue!t! to # i!p !er?er running in # !ep#r#te proce!!. /or thi! ch#pter, you@ll u!e # ?er!ion o' the open-!ource Web !er?er %llegroSer?e, origin#lly 6ritten by Dohn /oder#ro #t /r#nA Inc.. %llegroSer?e i! included in the ?er!ion o' %llegro #?#il#ble 'ro* /r#nA 'or u!e 6ith thi! boo9. I' you@re not u!ing %llegro, you c#n u!e Port#ble%llegroSer?e, # 'riendly 'or9 o' the
%llegroSer?e code b#!e, 6hich include! #n %llegro co*p#tibility l#yer th#t #llo6! Port#ble%llegroSer?e to run on *o!t Co**on i!p!. &he code you@ll 6rite in thi! ch#pter #nd in Ch#pter 2) !hould run in both ?#nill# %llegroSer?e #nd Port#ble%llegroSer?e. %llegroSer?e pro?ide! # progr#**ing *odel !i*il#r in !pirit to D#?# Ser?let!--e#ch ti*e # bro6!er reFue!t! # p#ge, %llegroSer?e p#r!e! the reFue!t #nd loo9! up #n ob<ect, c#lled #n entit0, 6hich h#ndle! the reFue!t. So*e entity cl#!!e! pro?ided #! p#rt o' %llegroSer?e 9no6 ho6 to !er?e !t#tic content-either indi?idu#l 'ile! or the content! o' # directory tree. 5ther!, the one! I@ll !pend *o!t o' thi! ch#pter di!cu!!ing, run #rbitr#ry i!p code to gener#te the re!pon!e.2 7ut be'ore I get to th#t, you need to 9no6 ho6 to !t#rt %llegroSer?e #nd !et it up to !er?e # 'e6 'ile!. &he 'ir!t !tep i! to lo#d the %llegroSer?e code into your i!p i*#ge. In %llegro, you c#n !i*ply type 1re@'ire#:aserve3. In other i!p! Bor in %llegroC, you c#n lo#d Port#ble%llegroSer?e by lo#ding the 'ile 98,FILL.lisp #t the top o' the portableaserve directory tree. o#ding %llegroSer?e 6ill cre#te three ne6 p#c9#ge!, 8-F.I,-.K-, 8-F.:F%L.J-8-.IF;., #nd 8-F.I,-.K-.$L9-8F., %'ter lo#ding the !er?er, you !t#rt it 6ith the 'unction start in the 8-F.I,-.K- p#c9#ge. &o h#?e e#!y #cce!! to the !y*bol! e.ported 'ro* 8-F.I,-.K-, 'ro* $;%.J9JI%;8M-H,.:F%L B# p#c9#ge I@ll di!cu!! in # *o*entC, #nd 'ro* the re!t o' Co**on i!p, you !hould cre#te # ne6 p#c9#ge to pl#y in li9e thi!:
$L-+,-./#1de(pac&age#:com.gigamon&e?s.web ############1:'se#:cl#:net.aserve#:com.gigamon&e?s.html33 NOFhe#$;%.J9JI%;8M-H,.W-L#pac&age/
:o6 you c#n u!e the e.ported n#*e! 'ro* 8-F.I,-.K- 6ithout Fu#li'ic#tion. &he 'unction start !t#rt! the !er?er. It t#9e! Fuite # nu*ber o' 9ey6ord p#r#*eter!, but the only one you need to p#!! i! :port, 6hich !peci'ie! the port to li!ten on. 4ou !hould prob#bly u!e # high port !uch #! 2001 in!te#d o' the de'#ult port 'or >&&P !er?er!, ,0, bec#u!e on 8ni.-deri?ed oper#ting !y!te*! only the root u!er c#n li!ten on port! belo6 102-. &o run %llegroSer?e li!tening on port ,0 on 8ni., you@d need to !t#rt i!p #! root #nd then u!e the :set'id #nd :setgid p#r#*eter! to tell start to !6itch it! identity #'ter opening the port. 4ou c#n !t#rt # !er?er li!tening on port 2001 li9e thi!:
W-L/#1start#:port#! 03 NOW,-.K-.#port#! 0#P#N)Q!"00cQ!/
&he !er?er i! no6 running in your i!p. It@! po!!ible you@ll get #n error th#t !#y! !o*ething #bout Hport #lre#dy in u!eH 6hen you try to !t#rt the !er?er. &hi! *e#n! port 2001 i! #lre#dy in u!e by !o*e other !er?er on your *#chine. In th#t c#!e, the !i*ple!t 'i. i! to u!e # di''erent port, !upplying # di''erent #rgu*ent to start #nd then u!ing th#t ?#lue in!te#d o' 2001 in the 8$ ! u!ed throughout thi! ch#pter. 4ou c#n continue to inter#ct 6ith i!p ?i# the $(P bec#u!e %llegroSer?e !t#rt! it! o6n thre#d! to h#ndle reFue!t! 'ro* bro6!er!. &hi! *e#n!, #*ong other thing!, th#t you c#n u!e the $(P to get # ?ie6 into the gut! o' your !er?er 6hile it@! running, 6hich *#9e! debugging #nd te!ting # lot e#!ier th#n i' the !er?er i! # co*plete bl#c9 bo..
%!!u*ing you@re running i!p on the !#*e *#chine #! your bro6!er, you c#n chec9 th#t the !er?er i! up #nd running by pointing your bro6!er #t http://localhost:! 0/. %t thi! point you !hould get # p#ge-not-'ound error *e!!#ge in the bro6!er !ince you h#?en@t publi!hed #nything yet. 7ut the error *e!!#ge 6ill be 'ro* %llegroSer?eG it@ll !#y !o #t the botto* o' the p#ge. 5n the other h#nd, i' the bro6!er di!pl#y! #n error di#log th#t !#y! !o*ething li9e H&he connection 6#! re'u!ed 6hen #tte*pting to cont#ct loc#lho!t:2001,H it *e#n! either th#t the !er?er i!n@t running or th#t you !t#rted it 6ith # di''erent port th#n 2001. :o6 you c#n publi!h !o*e 'ile!. Suppo!e you h#?e # 'ile hello.html in the directory /tmp/html 6ith the 'ollo6ing content!:
Ohtml/ ##Ohead/ ##Otitle/:elloO/title/ ##O/head/ ##Obod?/ ##Op/:ello5#worldAO/p/ ##O/bod?/ O/html/
&he :path #rgu*ent i! the p#th th#t 6ill #ppe#r in the 8$ reFue!ted by the bro6!er, 6hile the :(ile #rgu*ent i! the n#*e o' the 'ile in the 'ile !y!te*. %'ter e?#lu#ting the p'blish-(ile e.pre!!ion, you c#n point your bro6!er to http://localhost:! 0/hello.html, #nd it !hould di!pl#y # p#ge !o*ething li9e /igure 20-2.
0/hello.html
4ou could #l!o publi!h # 6hole directory tree o' 'ile! u!ing the p'blish-director? 'unction. /ir!t let@! cle#r out the #lre#dy publi!hed entity 6ith the 'ollo6ing c#ll to p'blish-(ile:
W-L/#1p'blish-(ile#:path#4/hello.html4#:remove#t3 89L
:o6 you c#n publi!h the 6hole /tmp/html/ directory B#nd #ll it! !ubdirectorie!C 6ith the p'blish-director? 'unction.
W-L/#1p'blish-director?#:pre(i)#4/4#:destination#4/tmp/html/43 NO8-F.I,-.K-::<9.-$F;.H--8F9FH#P#N)Q!6!"aa!/
In thi! c#!e, the :pre(i) #rgu*ent !peci'ie! the beginning o' the p#th p#rt o' 8$ ! th#t !hould be h#ndled by thi! entity. &hu!, i' the !er?er recei?e! # reFue!t 'or http://localhost:! 0/(oo/bar.html, the p#th i! /(oo/bar.html, 6hich !t#rt! 6ith /. &hi! p#th i! then tr#n!l#ted to # 'ilen#*e by repl#cing the pre'i., /, 6ith the de!tin#tion, /tmp/html/. &hu!, the 8$ http://localhost:! 0/hello.html 6ill !till be tr#n!l#ted into # reFue!t 'or the 'ile /tmp/html/hello.html.
&he *#cro! with-http-response #nd with-http-bod? #re p#rt o' %llegroSer?e. &he 'or*er !t#rt! the proce!! o' gener#ting #n >&&P re!pon!e #nd c#n be u!ed, #! here, to !peci'y thing! !uch #! the type o' content th#t 6ill be returned. It #l!o h#ndle! ?#riou! p#rt! o' >&&P !uch #! de#ling 6ith I'3odi'ied-Since reFue!t!. &he with-http-bod? #ctu#lly !end! the >&&P re!pon!e he#der! #nd then e.ecute! it! body, 6hich !hould cont#in code th#t gener#te! the content o' the reply. Within withhttp-response but be'ore the with-http-bod?, you c#n #dd or ch#nge >&&P he#der! to be !ent in the reply. &he 'unction re@'est-repl?-stream i! #l!o p#rt o' %llegroSer?e #nd return! the !tre#* to 6hich you !hould 6rite output intended to be !ent to the bro6!er. %! thi! 'unction !ho6!, you c#n <u!t u!e FORMAT to print >&3 to the !tre#* returned by re@'estrepl?-stream. In the ne.t !ection, I@ll !ho6 you *ore con?enient 6#y! to progr#**#tic#lly
%! it doe! in the p'blish-(ile 'unction, the :path #rgu*ent !peci'ie! the p#th p#rt o' the 8$ th#t 6ill re!ult in thi! 'unction being in?o9ed. &he :('nction #rgu*ent !peci'ie! either the n#*e or #n #ctu#l 'unction ob<ect. 8!ing the n#*e o' # 'unction, #! !ho6n here, #llo6! you to rede'ine the 'unction l#ter 6ithout republi!hing #nd h#?e %llegroSer?e u!e the ne6 'unction de'inition. %'ter e?#lu#ting the c#ll to p'blish, you c#n point your bro6!er #t http://# localhost:! 0/random-n'mber to get # p#ge 6ith # r#ndo* nu*ber on it, #! !ho6n in /igure 20-3.
0/random-n'mber
&enerating .T+L
%lthough u!ing FORMAT to e*it >&3 6or9! 'ine 'or the !i*ple p#ge! I@?e di!cu!!ed !o '#r, #! you !t#rt building *ore el#bor#te p#ge! it@d be nice to h#?e # *ore conci!e 6#y to gener#te >&3 . Se?er#l libr#rie! #re #?#il#ble 'or gener#ting >&3 'ro* #n !-e.pre!!ion repre!ent#tion including one, ht*lgen, th#t@! included 6ith %llegroSer?e. In thi! ch#pter you@ll u!e # libr#ry c#lled /55,10 6hich i! loo!ely *odeled on /r#nA@! ht*lgen #nd 6ho!e i*ple*ent#tion you@ll loo9 #t in *ore det#il in Ch#pter! 30 #nd 31. /or no6, ho6e?er, you <u!t need to 9no6 ho6 to u!e /55. =ener#ting >&3 'ro* 6ithin i!p i! Fuite n#tur#l !ince !-e.pre!!ion! #nd >&3 #re e!!enti#lly i!o*orphic. 4ou c#n repre!ent >&3 ele*ent! 6ith !-e.pre!!ion! by tre#ting e#ch ele*ent in >&3 #! # li!t Ht#ggedH 6ith #n #ppropri#te 'ir!t ele*ent, !uch #! # 9ey6ord !y*bol o' the !#*e n#*e #! the >&3 t#g. &hu!, the >&3 Op/(ooO/p/ i! repre!ented by the !-e.pre!!ion 1:p#4(oo43. 7ec#u!e >&3 ele*ent! ne!t the !#*e 6#y li!t! in !-e.pre!!ion! do, thi! !che*e e.tend! to *ore co*ple. >&3 . /or in!t#nce, thi! >&3 :
Ohtml/ ##Ohead/ ##Otitle/:elloO/title/ ##O/head/
>&3 ele*ent! 6ith #ttribute! co*plic#te thing! # bit but not in #n in!ur*ount#ble 6#y. /55 !upport! t6o 6#y! o' including #ttribute! in # t#g. 5ne i! to !i*ply 'ollo6 the 'ir!t ite* o' the li!t 6ith 9ey6ord;?#lue p#ir!. &he 'ir!t ele*ent th#t 'ollo6! # 9ey6ord;?#lue p#ir th#t@! not it!el' # 9ey6ord !y*bol *#r9! the beginning o' the ele*ent@! content!. &hu!, you@d repre!ent thi! >&3 :
Oa#hre(=4(oo.html4/Fhis#is#a#lin&O/a/
&he other !ynt#. /55 !upport! i! to group the t#g n#*e #nd #ttribute! into their o6n li!t li9e thi!:
11:a#:hre(#4(oo.html43#4Fhis#is#lin&.43
/55 c#n u!e the !-e.pre!!ion repre!ent#tion o' >&3 in t6o 6#y!. &he 'unction emit-html t#9e! #n >&3 !-e.pre!!ion #nd output! the corre!ponding >&3 .
W-L/#1emit-html#C1:html#1:head#1:title#4:ello433#1:bod?#1:p#4:ello5#worldA43333 Ohtml/ ##Ohead/ ####Otitle/:elloO/title/ ##O/head/ ##Obod?/ ####Op/:ello5#worldAO/p/ ##O/bod?/ O/html/ F
>o6e?er, emit-html i!n@t #l6#y! the *o!t e''icient 6#y to gener#te >&3 bec#u!e it! #rgu*ent *u!t be # co*plete !-e.pre!!ion repre!ent#tion o' the >&3 to be gener#ted. While it@! e#!y to build !uch # repre!ent#tion, it@! not #l6#y! p#rticul#rly e''icient. /or in!t#nce, !uppo!e you 6#nted to *#9e #n >&3 p#ge cont#ining # li!t o' 10,000 r#ndo* nu*ber!. 4ou could build the !-e.pre!!ion u!ing # b#c9Fuote te*pl#te #nd then p#!! it to emit-html li9e thi!:
1emit-html ##B1:html #####1:head #######1:title#4.andom#n'mbers433 #####1:bod?# #######1:h0#4.andom#n'mbers43 #######1:p#5P1loop#repeat#0 #collect#1random#0
3#collect#4#433333
>o6e?er, thi! h#! to build # tree cont#ining # 10,000-ele*ent li!t be'ore it c#n e?en !t#rt e*itting >&3 , #nd the 6hole !-e.pre!!ion 6ill beco*e g#rb#ge #! !oon #! the >&3 i! e*itted. &o #?oid thi!
ine''iciency, /55 #l!o pro?ide! # *#cro html, 6hich #llo6! you to e*bed bit! o' i!p code in the *iddle o' #n >&3 !-e.pre!!ion. iter#l ?#lue! !uch #! !tring! #nd nu*ber! in the input to html #re interpol#ted into the output >&3 . i9e6i!e, !y*bol! #re tre#ted #! ?#ri#ble re'erence!, #nd code i! gener#ted to e*it their ?#lue #t runti*e. &hu!, both o' the!e:
1html#1:p#4(oo433 1let#11)#4(oo433#1html#1:p#)333
i!t 'or*! th#t don@t !t#rt 6ith # 9ey6ord !y*bol #re #!!u*ed to be code #nd #re e*bedded in the gener#ted code. %ny ?#lue! the e*bedded code return! 6ill be ignored, but the code c#n e*it *ore >&3 by c#lling html it!el'. /or in!t#nce, to e*it the content! o' # li!t in >&3 , you *ight 6rite thi!:
1html#1:'l#1dolist#1item#1list#0#!#333#1html#1:li#item33333
I' you 6#nt to e*it the ?#lue o' # li!t 'or*, you *u!t 6r#p it in the p!eudot#g :print. &hu!, thi! e.pre!!ion:
1html#1:p#12#0#!333
5r you could co*pute the ?#lue #nd !tore it in # ?#ri#ble out!ide the c#ll to html li9e thi!:
1let#11)#12#0#!333#1html#1:p#)333
&hu!, you c#n u!e the html *#cro to gener#te the li!t o' r#ndo* nu*ber! li9e thi!:
1html ##1:html ####1:head ######1:title#4.andom#n'mbers433 ####1:bod?# ######1:h0#4.andom#n'mbers43 ######1:p#1loop#repeat#0 #do#1html#1:print#1random#0
33#4#4333333
&he *#cro ?er!ion 6ill be Fuite # bit *ore e''icient th#n the emit-html ?er!ion. :ot only do you ne?er h#?e to gener#te #n !-e.pre!!ion repre!enting the 6hole p#ge, #l!o *uch o' the 6or9 th#t emithtml doe! #t runti*e to interpret the !-e.pre!!ion 6ill be done once, 6hen the *#cro i! e.p#nded, r#ther th#n e?ery ti*e the code i! run. 4ou c#n control 6here the output gener#ted by both html #nd emit-html i! !ent 6ith the *#cro with-html-o'tp't, 6hich i! p#rt o' the /55 libr#ry. &hu!, you c#n u!e the with-htmlo'tp't #nd html *#cro! 'ro* /55 to re6rite random-n'mber li9e thi!:
1de('n#random-n'mber#1re@'est#entit?3 ##1with-http-response#1re@'est#entit?#:content-t?pe#4te)t/html43 ####1with-http-bod?#1re@'est#entit?3 ######1with-html-o'tp't#11re@'est-repl?-stream#re@'est33 ########1html ##########1:html ############1:head#1:title#4.andom433 ############1:bod? ##############1:p#4.andom#n'mber:#4#1:print#1random#0 3333333333
.T+L +acros
%nother 'e#ture o' /55 i! th#t it #llo6! you to de'ine >&3 H*#cro!H th#t c#n tr#n!l#te #rbitr#ry 'or*! into >&3 !-e.pre!!ion! th#t the html *#cro under!t#nd!. /or in!t#nce, !uppo!e you 'reFuently 'ind your!el' 6riting p#ge! o' thi! 'or*:
1:html ##1:head#1:title#4,ome#title433 ##1:bod? ####1:h0#4,ome#title43 ####...!stuff!...33
4ou could de'ine #n >&3 *#cro to c#pture th#t p#ttern li9e thi!:
1de(ine-html-macro#:standard-page#11>&e?#title3#>bod?#bod?3 ##B1:html #####1:head#1:title#5title33 #####1:bod? ######1:h0#5title3 ######5Pbod?333
:o6 you c#n u!e the Ht#gH :standard-page in your !-e.pre!!ion >&3 , #nd it@ll be e.p#nded be'ore being interpreted or co*piled. /or in!t#nce, the 'ollo6ing:
1html#1:standard-page#1:title#4:ello43#1:p#4:ello5#world.4333
3uery "ara$eters
5' cour!e, gener#ting >&3 output i! only h#l' o' Web progr#**ing. &he other thing you need to do i! get input 'ro* the u!er. %! I di!cu!!ed in the H% 30-Second Intro to Ser?er-Side Web Progr#**ingH !ection, 6hen # bro6!er reFue!t! # p#ge 'ro* # Web !er?er, it c#n !end Fuery p#r#*eter! in the 8$ #nd po!t d#t#, both o' 6hich #ct #! input to the !er?er-!ide code. %llegroSer?e, li9e *o!t Web progr#**ing 'r#*e6or9!, t#9e! c#re o' p#r!ing both the!e !ource! o' input 'or you. 7y the ti*e your publi!hed 'unction! #re c#lled, #ll the 9ey;?#lue p#ir! 'ro* the Fuery !tring #nd;or po!t d#t# h#?e been decoded #nd pl#ced into #n #li!t th#t you c#n retrie?e 'ro* the reFue!t ob<ect 6ith the 'unction re@'est-@'er?. &he 'ollo6ing 'unction return! # p#ge !ho6ing #ll the Fuery p#r#*eter! it recei?e!:
1de('n#show-@'er?-params#1re@'est#entit?3 ##1with-http-response#1re@'est#entit?#:content-t?pe#4te)t/html43 ####1with-http-bod?#1re@'est#entit?3 ######1with-html-o'tp't#11re@'est-repl?-stream#re@'est33 ########1html ##########1:standard-page ###########1:title#4Z'er?#Tarameters43 ###########1i(#1re@'est-@'er?#re@'est3 #############1html# ###############1:table#:border#0 #######################1loop#(or#1&#.#v3#in#1re@'est-@'er?#re@'est3 ##########################do#1html#1:tr#1:td#&3#1:td#v333333 #############1html#1:p#48o#@'er?#parameters.4333333333 1p'blish#:path#4/show-@'er?-params4#:('nction#Cshow-@'er?-params3
I' you gi?e your bro6!er # 8$ 6ith # Fuery !tring in it li9e the 'ollo6ing:
http://localhost:! 0/show-@'er?-params?(oo=bar>ba*=0
you !hould get b#c9 # p#ge !i*il#r to the one !ho6n in /igure 20--.
0/show-@'er?-params?(oo=bar>ba*=0
&o gener#te !o*e po!t d#t#, you need #n >&3 'or*. &he 'ollo6ing 'unction gener#te! # !i*ple 'or*, 6hich !ub*it! it! d#t# to show-@'er?-params:
1de('n#simple-(orm#1re@'est#entit?3 ##1with-http-response#1re@'est#entit?#:content-t?pe#4te)t/html43 ####1with-http-bod?#1re@'est#entit?3 ######1let#11Uhtml-o'tp'tU#1re@'est-repl?-stream#re@'est333 ########1html ##########1:html ############1:head#1:title#4,imple#Eorm433 ############1:bod? #############1:(orm#:method#4T;,F4#:action#4/show-@'er?-params4 ###############1:table ################1:tr#1:td#4Eoo43 #####################1:td#1:inp't#:name#4(oo4#:si*e#! 333 ################1:tr#1:td#4Tassword43 #####################1:td#1:inp't#:name#4password4#:t?pe#4password4#:si*e#! 3333 ###############1:p#1:inp't#:name#4s'bmit4#:t?pe#4s'bmit4#:val'e#4;&a?43 ###################1:inp't#::t?pe#4reset4#:val'e#4.eset43333333333 1p'blish#:path#4/simple-(orm4#:('nction#Csimple-(orm3
I' you 'ill in the 'or* 6ith the H#bcH #nd Hde'H ?#lue!, clic9ing the 59#y button !hould t#9e you to # p#ge li9e the one in /igure 20-0.
0/simple-(orm
/igure 20-0. $e!ult o' !ub*itting the !i*ple 'or* >o6e?er, *o!t o' the ti*e you 6on@t need to iter#te o?er #ll the Fuery p#r#*eter!G you@ll 6#nt to pic9 out indi?idu#l p#r#*eter!. /or in!t#nce, you *ight 6#nt to *odi'y random-n'mber !o the li*it ?#lue you p#!! to RANDOM c#n be !upplied ?i# # Fuery p#r#*eter. In th#t c#!e, you u!e the 'unction re@'est-@'er?-val'e, 6hich t#9e! the reFue!t ob<ect #nd the n#*e o' the p#r#*eter 6ho!e ?#lue you 6#nt #nd return! the ?#lue #! # !tring or NIL i' no !uch p#r#*eter h#! been !upplied. % p#r#*eteriA#ble ?er!ion o' random-n'mber *ight loo9 li9e thi!:
1de('n#random-n'mber#1re@'est#entit?3 ##1with-http-response#1re@'est#entit?#:content-t?pe#4te)t/html43 ####1with-http-bod?#1re@'est#entit?3 ######1letU#11Uhtml-o'tp'tU#1re@'est-repl?-stream#re@'est33 #############1limit-string#1or#1re@'est-@'er?-val'e#4limit4#re@'est3#4433 #############1limit#1or#1parse-integer#limit-string#:j'n&-allowed#t3#0 333 ########1html ##########1:html ############1:head#1:title#4.andom433 ############1:bod? ##############1:p#4.andom#n'mber:#4#1:print#1random#limit3333333333
7ec#u!e re@'est-@'er?-val'e c#n return either NIL or #n e*pty !tring, you h#?e to de#l 6ith both tho!e c#!e! 6hen p#r!ing the p#r#*eter into # nu*ber to p#!! to RANDOM. 4ou c#n de#l 6ith # NIL ?#lue 6hen you bind limit-string, binding it to 44 i' there@! no Hli*itH Fuery p#r#*eter. &hen you c#n u!e the :j'n&-allowed #rgu*ent to PARSE-INTEGER to en!ure th#t it return! either NIL Bi' it c#n@t p#r!e #n integer 'ro* the !tring gi?enC or #n integer. In the !ection H% S*#ll %pplic#tion /r#*e6or9,H you@ll de?elop !o*e *#cro! to *#9e it e#!ier to de#l 6ith gr#bbing Fuery p#r#*eter! #nd con?erting the* to ?#riou! type!.
#ookies
In %llegroSer?e you c#n !end # Set-Coo9ie he#der th#t tell! the bro6!er to !#?e # coo9ie #nd !end it #long 6ith !ub!eFuent reFue!t! by c#lling the 'unction set-coo&ie-header 6ithin the body o' with-http-response but be'ore the c#ll to with-http-bod?. &he 'ir!t #rgu*ent to the 'unction i! the reFue!t ob<ect, #nd the re*#ining #rgu*ent! #re 9ey6ord #rgu*ent! u!ed to !et the ?#riou! propertie! o' the coo9ie. &he only t6o you *u!t p#!! #re the :name #nd :val'e #rgu*ent!,
both o' 6hich !hould be !tring!. &he other po!!ible #rgu*ent! th#t #''ect the coo9ie !ent to the bro6!er #re :e)pires, :path, :domain, #nd :sec're. 5' the!e, you need to 6orry only #bout :e)pires. It control! ho6 long the bro6!er !hould !#?e the coo9ie. I' :e)pires i! NIL Bthe de'#ultC, the bro6!er 6ill !#?e the coo9ie only until it e.it!. 5ther po!!ible ?#lue! #re :never, 6hich *e#n! the coo9ie !hould be 9ept 'ore?er, or # uni?er!#l ti*e #! returned by GET-UNIVERSAL-TIME or ENCODE-UNIVERSAL-TIME. %n :e)pires o' Aero tell! the client to i**edi#tely di!c#rd #n e.i!ting coo9ie.11 %'ter you@?e !et # coo9ie, you c#n u!e the 'unction get-coo&ie-val'es to get #n #li!t cont#ining one n#*e;?#lue p#ir 'or e#ch coo9ie !ent by the bro6!er. /ro* th#t #li!t, you c#n pic9 out indi?idu#l coo9ie ?#lue! u!ing ASSOC #nd CDR. &he 'ollo6ing 'unction !ho6! the n#*e! #nd ?#lue! o' #ll the coo9ie! !ent by the bro6!er:
1de('n#show-coo&ies#1re@'est#entit?3 ##1with-http-response#1re@'est#entit?#:content-t?pe#4te)t/html43 ####1with-http-bod?#1re@'est#entit?3 ######1with-html-o'tp't#11re@'est-repl?-stream#re@'est33 ########1html ##########1:standard-page ###########1:title#4$oo&ies43 ###########1i(#1n'll#1get-coo&ie-val'es#re@'est33 #############1html#1:p#48o#coo&ies.433 #############1html# ###############1:table #################1loop#(or#1&e?#.#val'e3#in#1get-coo&ie-val'es#re@'est3 ####################do#1html#1:tr#1:td#&e?3#1:td#val'e3333333333333 1p'blish#:path#4/show-coo&ies4#:('nction#Cshow-coo&ies3
&he 'ir!t ti*e you lo#d the p#ge http://localhost:! 0/show-coo&ies it !hould !#y H:o coo9ie!H #! !ho6n in /igure 20-2 !ince you h#?en@t !et #ny yet.
&o !et # coo9ie, you need #nother 'unction, !uch #! the 'ollo6ing:
1de('n#set-coo&ie#1re@'est#entit?3 ##1with-http-response#1re@'est#entit?#:content-t?pe#4te)t/html43
I' you enter the 8$ http://localhost:! 0/set-coo&ie, your bro6!er !hould di!pl#y # p#ge li9e the one in /igure 20-,. %ddition#lly, the !er?er 6ill !end # Set-Coo9ie he#der 6ith # coo9ie n#*ed H3yCoo9ieH 6ith H% coo9ie ?#lueH #! it! ?#lue. I' you clic9 the lin9 Loo$ at coo$ie jar, you@ll be t#9en to the /show-coo&ies p#ge 6here you@ll !ee the ne6 coo9ie, #! !ho6n in /igure 20-). 7ec#u!e you didn@t !peci'y #n :e)pires #rgu*ent, the bro6!er 6ill continue to !end the coo9ie 6ith e#ch reFue!t until you Fuit the bro6!er.
0/set-coo&ie
6here the bod0 i! the code to e*it the >&3 o' the p#ge. It@ll be 6r#pped in # c#ll to /55@! html *#cro, !o 'or !i*ple p#ge! it *ight cont#in nothing but !-e.pre!!ion >&3 . Within the body, the Fuery p#r#*eter ?#ri#ble! 6ill be bound to ?#lue! o' Fuery p#r#*eter! 6ith the !#*e n#*e or 'ro* # coo9ie. In the !i*ple!t c#!e, # Fuery p#r#*eter@! ?#lue 6ill be the !tring t#9en 'ro* the Fuery p#r#*eter or po!t d#t# 'ield o' the !#*e n#*e. I' the Fuery p#r#*eter i! !peci'ied 6ith # li!t, you c#n #l!o !peci'y #n #uto*#tic type con?er!ion, # de'#ult ?#lue, #nd 6hether to loo9 'or #nd !#?e the ?#lue o' the p#r#*eter in # coo9ie. &he co*plete !ynt#. 'or # 4uer0)parameter i! #! 'ollo6!:
name#X#1name#type#Ddefault-valueG#DstickinessG3
&he t0pe *u!t be # n#*e recogniAed by de(ine-'rl-('nction. I@ll di!cu!! in # *o*ent ho6 to de'ine ne6 type!. &he default)value *u!t be # ?#lue o' the gi?en type. /in#lly, stic$iness, i' !upplied, indic#te! th#t the p#r#*eter@! ?#lue !hould be t#9en 'ro* #n #ppropri#tely n#*ed coo9ie i' no Fuery p#r#*eter i! !upplied #nd th#t # Set-Coo9ie he#der !hould be !ent in the re!pon!e th#t !#?e! the ?#lue in the coo9ie o' the !#*e n#*e. &hu!, # !tic9y p#r#*eter, #'ter being e.plicitly !upplied # ?#lue ?i# # Fuery p#r#*eter, 6ill 9eep th#t ?#lue on !ub!eFuent reFue!t! o' the p#ge e?en 6hen no Fuery p#r#*eter i! !upplied. &he n#*e o' the coo9ie u!ed depend! on the ?#lue o' stic$iness: 6ith # ?#lue o' :global, the coo9ie 6ill be n#*ed the !#*e #! the p#r#*eter. &hu!, di''erent 'unction! th#t u!e glob#lly !tic9y p#r#*eter! 6ith the !#*e n#*e 6ill !h#re the ?#lue. I' stic$iness i! :pac&age, then the coo9ie n#*e i! con!tructed 'ro* the n#*e o' the p#r#*eter #nd the p#c9#ge o' the 'unction@! n#*eG thi! #llo6! 'unction! in the !#*e p#c9#ge to !h#re ?#lue! but not h#?e to 6orry #bout !to*ping on p#r#*eter! o' 'unction! in other p#c9#ge!. /in#lly, # p#r#*eter 6ith # stic$iness ?#lue o' :local 6ill u!e # coo9ie *#de 'ro* the n#*e o' the p#r#*eter, the p#c9#ge o' the 'unction n#*e, #nd the 'unction n#*e,
*#9ing it uniFue to th#t 'unction. /or in!t#nce, you c#n u!e de(ine-'rl-('nction to repl#ce the pre?iou! ele?en-line de'inition o' random-page 6ith thi! 'i?e-line ?er!ion:
1de(ine-'rl-('nction#random-n'mber#1re@'est#1limit#integer#0 ##1:html ####1:head#1:title#4.andom433 ####1:bod? ######1:p#4.andom#n'mber:#4#1:print#1random#limit333333 33
I' you 6#nted the li*it #rgu*ent to be !tic9y, you could ch#nge the li*it decl#r#tion to 1limit# integer#0 #:local3.
The I$p%e$entation
I@ll e.pl#in the i*ple*ent#tion o' de(ine-'rl-('nction 'ro* the top do6n. &he *#cro it!el' loo9! li9e thi!:
1de(macro#de(ine-'rl-('nction#1name#1re@'est#>rest#params3#>bod?#bod?3 ##1with-gens?ms#1entit?3 ####1let#11params#1mapcar#NCnormali*e-param#params333 ######B1progn #########1de('n#5name#15re@'est#5entit?3 ###########1with-http-response#15re@'est#5entit?#:content-t?pe#4te)t/html43 #############1letU#15P1param-bindings#name#re@'est#params33 ###############5P1set-coo&ies-code#name#re@'est#params3 ###############1with-http-bod?#15re@'est#5entit?3 #################1with-html-o'tp't#11re@'est-repl?-stream#5re@'est33 ###################1html#5Pbod?333333 #########1p'blish#:path#51(ormat#nil#4/717a734#name3#:('nction#C5name33333
et@! t#9e it bit by bit, !t#rting 6ith the 'ir!t 'e6 line!.
1de(macro#de(ine-'rl-('nction#1name#1re@'est#>rest#params3#>bod?#bod?3 ##1with-gens?ms#1entit?3 ####1let#11params#1mapcar#NCnormali*e-param#params333
8p to here you@re <u!t getting re#dy to gener#te code. 4ou GENSYM # !y*bol to u!e l#ter #! the n#*e o' the entity p#r#*eter in the DEFUN. &hen you nor*#liAe the p#r#*eter!, con?erting pl#in !y*bol! to li!t 'or* u!ing thi! 'unction:
1de('n#normali*e-param#1param3 ##1et?pecase#param ####1list#param3 ####1s?mbol#B15param#string#nil#nil3333
In other 6ord!, decl#ring # p#r#*eter 6ith <u!t # !y*bol i! the !#*e #! decl#ring # non!tic9y, !tring p#r#*eter 6ith no de'#ult ?#lue. &hen co*e! the PROGN. 4ou *u!t e.p#nd into # PROGN bec#u!e you need to gener#te code to do t6o thing!: de'ine # 'unction 6ith DEFUN #nd c#ll p'blish. 4ou !hould de'ine the 'unction 'ir!t !o i' there@! #n error in the de'inition, the 'unction 6on@t be publi!hed. &he 'ir!t t6o line! o' the DEFUN #re <u!t boilerpl#te.
1de('n#5name#15re@'est#5entit?3
##1with-http-response#15re@'est#5entit?#:content-t?pe#4te)t/html43##
:o6 you do the re#l 6or9. &he 'ollo6ing t6o line! gener#te the binding! 'or the p#r#*eter! !peci'ied in de(ine-'rl-('nction other th#n re@'est #nd the code th#t c#ll! set-coo&ie-header 'or the !tic9y p#r#*eter!. 5' cour!e, the re#l 6or9 i! done by helper 'unction! th#t you@ll loo9 #t in # *o*ent.12
####1letU#15P1param-bindings#name#re@'est#params33 ######5P1set-coo&ies-code#name#re@'est#params3
&he re!t i! <u!t *ore boilerpl#te, putting the body 'ro* the de(ine-'rl-('nction de'inition in the #ppropri#te conte.t o' with-http-bod?, with-html-o'tp't, #nd html *#cro!. &hen co*e! the c#ll to p'blish.
###1p'blish#:path#51(ormat#nil#4/717a734#name3#:('nction#C5name3
&he e.pre!!ion 1(ormat#nil#4/717a734#name3 i! e?#lu#ted #t *#cro e.p#n!ion ti*e, gener#ting # !tring con!i!ting o' ;, 'ollo6ed by #n #ll-lo6erc#!e ?er!ion o' the n#*e o' the 'unction you@re #bout to de'ine. &h#t !tring beco*e! the :path #rgu*ent to publi!h, 6hile the 'unction n#*e i! interpol#ted #! the :('nction #rgu*ent. :o6 let@! loo9 #t the helper 'unction! u!ed to gener#te the DEFUN 'or*. &o gener#te p#r#*eter binding!, you need to loop o?er the params #nd collect # !nippet o' code 'or e#ch one, gener#ted by param-binding. &h#t !nippet 6ill be # li!t cont#ining the n#*e o' the ?#ri#ble to bind #nd the code th#t 6ill co*pute the ?#lue o' th#t ?#ri#ble. &he e.#ct 'or* o' code u!ed to co*pute the ?#lue 6ill depend on the type o' the p#r#*eter, 6hether it@! !tic9y, #nd the de'#ult ?#lue, i' #ny. 7ec#u!e you #lre#dy nor*#liAed the p#r#*!, you c#n u!e DESTRUCTURING-BIND to t#9e the* #p#rt in parambinding.
1de('n#param-bindings#1('nction-name#re@'est#params3 ##1loop#(or#param#in#params #####collect#1param-binding#('nction-name#re@'est#param333 1de('n#param-binding#1('nction-name#re@'est#param3 ##1destr'ct'ring-bind#1name#t?pe#>optional#de(a'lt#stic&?3#param ####1let#11@'er?-name#1s?mbol-/@'er?-name#name33 ##########1coo&ie-name#1s?mbol-/coo&ie-name#('nction-name#name#stic&?333 ######B15name#1or# ###############1string-/t?pe#C5t?pe#1re@'est-@'er?-val'e#5@'er?-name#5re@'est33 ###############5P1i(#coo&ie-name #####################1list#B1string-/t?pe#C5t?pe#1get-coo&ie-val'e#5re@'est# 5coo&ie-name3333 ###############5de(a'lt33333
&he 'unction string-/t?pe, 6hich you u!e to con?ert !tring! obt#ined 'ro* the Fuery p#r#*eter! #nd coo9ie! to the de!ired type, i! # generic 'unction 6ith the 'ollo6ing !ign#ture:
1de(generic#string-/t?pe#1t?pe#val'e33
&o *#9e # p#rticul#r n#*e u!#ble #! # type n#*e 'or # Fuery p#r#*eter, you <u!t need to de'ine # *ethod on string-/t?pe. 4ou@ll need to de'ine #t le#!t # *ethod !peci#liAed on the !y*bol string !ince th#t@! the de'#ult type. 5' cour!e, th#t@! pretty e#!y. Since bro6!er! !o*eti*e! !ub*it 'or*! 6ith e*pty !tring! to indic#te no ?#lue 6#! !upplied 'or # p#rticul#r ?#lue, you@ll 6#nt to con?ert #n e*pty !tring to NIL #! thi! *ethod doe!:
1de(method#string-/t?pe#11t?pe#1e@l#Cstring33#val'e3 ##1and#1pl'sp#1length#val'e33#val'e33
4ou c#n #dd con?er!ion! 'or other type! needed by your #pplic#tion. /or in!t#nce, to *#9e integer u!#ble #! # Fuery p#r#*eter type !o you c#n h#ndle the limit p#r#*eter o' random-page, you *ight de'ine thi! *ethod:
1de(method#string-/t?pe#11t?pe#1e@l#Cinteger33#val'e3 ##1parse-integer#1or#val'e#443#:j'n&-allowed#t33
%nother helper 'unction u!ed in the code gener#ted by param-binding i! get-coo&ie-val'e, 6hich i! <u!t # bit o' !ug#r #round the get-coo&ie-val'es 'unction pro?ided by %llegroSer?e. It loo9! li9e thi!:
1de('n#get-coo&ie-val'e#1re@'est#name3 ##1cdr#1assoc#name#1get-coo&ie-val'es#re@'est3#:test#NCstring=333
&he 'unction! th#t co*pute the Fuery p#r#*eter #nd coo9ie! n#*e! #re !i*il#rly !tr#ight'or6#rd.
1de('n#s?mbol-/@'er?-name#1s?m3 ##1string-downcase#s?m33 1de('n#s?mbol-/coo&ie-name#1('nction-name#s?m#stic&?3 ##1let#11pac&age-name#1pac&age-name#1s?mbol-pac&age#('nction-name3333 ####1when#stic&? ######1ecase#stic&? ########1:global #########1string-downcase#s?m33 ########1:pac&age #########1(ormat#nil#4717a:7a734#pac&age-name#s?m33 ########1:local# #########1(ormat#nil#4717a:7a:7a734#pac&age-name#('nction-name#s?m333333
&o gener#te the code th#t !et! coo9ie! 'or !tic9y p#r#*eter!, you #g#in loop o?er the li!t o' p#r#*eter!, thi! ti*e collecting # !nippet o' code 'or e#ch !tic9y p#r#*. 4ou c#n u!e the when##nd collect#it# LOOP 'or*! to collect only the non-NIL ?#lue! returned by set-coo&ie-code.
1de('n#set-coo&ies-code#1('nction-name#re@'est#params3 ##1loop#(or#param#in#params #######when#1set-coo&ie-code#('nction-name#re@'est#param3#collect#it33 1de('n#set-coo&ie-code#1('nction-name#re@'est#param3 ##1destr'ct'ring-bind#1name#t?pe#>optional#de(a'lt#stic&?3#param ####1declare#1ignore#t?pe#de(a'lt33 ####1i(#stic&? ######B1when#5name# #########1set-coo&ie-header# ##########5re@'est ##########:name#51s?mbol-/coo&ie-name#('nction-name#name#stic&?3 ##########:val'e#1princ-to-string#5name333333
5ne o' the #d?#nt#ge! o' de'ining *#cro! in ter*! o' helper 'unction! li9e thi! i! th#t it@! e#!y to *#9e !ure the indi?idu#l bit! o' code you@re gener#ting loo9 right. /or in!t#nce, you c#n chec9 th#t the 'ollo6ing set-coo&ie-code:
1set-coo&ie-code#C(oo#Cre@'est#C1)#integer#! #:local33
%!!u*ing thi! code 6ill occur in # conte.t 6here ) i! the n#*e o' # ?#ri#ble, thi! loo9! good. 5nce #g#in, *#cro! h#?e #llo6ed you to di!till the code you need to 6rite do6n to it! e!!ence--in thi! c#!e, the d#t# you 6#nt to e.tr#ct 'ro* the reFue!t #nd the >&3 you 6#nt to gener#te. &h#t !#id, thi! 'r#*e6or9 i!n@t *e#nt to be the be-#ll #nd end-#ll o' Web #pplic#tion 'r#*e6or9!--it@! <u!t # little !ug#r to *#9e it # bit e#!ier to 6rite !i*ple #pp! li9e the one you@ll 6rite in Ch#pter 2). 7ut be'ore you c#n get to th#t, you need to 6rite the gut! o' the #pplic#tion 'or 6hich the Ch#pter 2) #pplic#tion 6ill be the u!er inter'#ce. 4ou@ll !t#rt in the ne.t ch#pter 6ith # !ouped-up ?er!ion o' the d#t#b#!e you 6rote in Ch#pter 3, thi! ti*e to 9eep tr#c9 o' I+3 d#t# e.tr#cted 'ro* 3P3 'ile!.
1$e#der!
ne6 to Web progr#**ing 6ill prob#bly need to !upple*ent thi! introduction 6ith # *ore indepth tutori#l or t6o. 4ou c#n 'ind # good !et o' online tutori#l! #t http://www.jmarshall.com/eas?/.
2
o#ding # !ingle Web p#ge *#y #ctu#lly in?ol?e *ultiple reFue!t!--to render the >&3 o' # p#ge cont#ining inline i*#ge!, the bro6!er *u!t reFue!t e#ch i*#ge indi?idu#lly #nd then in!ert e#ch into the #ppropri#te pl#ce in the rendered >&3 .
33uch
o' the co*ple.ity #round Web progr#**ing i! # re!ult o' trying to 6or9 #round thi! 'und#*ent#l li*it#tion in order to pro?ide # u!er e.perience th#t@! *ore li9e the inter#cti?ity pro?ided by de!9top #pplic#tion!.
-8n'ortun#tely,
d0namic i! !o*e6h#t o?erlo#ded in the Web 6orld. &he phr#!e D0namic BTML re'er! to >&3 cont#ining e*bedded code, u!u#lly in the l#ngu#ge D#?#Script, th#t c#n be e.ecuted in the bro6!er 6ithout 'urther co**unic#tion 6ith the Web !er?er. 8!ed 6ith !o*e di!cretion, +yn#*ic >&3 c#n i*pro?e the u!#bility o' # Web-b#!ed #pplic#tion !ince, e?en 6ith high-!peed Internet connection!, *#9ing # reFue!t to # Web !er?er, recei?ing the re!pon!e, #nd rendering the ne6 p#ge c#n t#9e # notice#ble #*ount o' ti*e. &o 'urther con'u!e thing!, dyn#*ic#lly gener#ted p#ge! Bin other 6ord!, gener#ted on the !er?erC could #l!o cont#in +yn#*ic >&3 Bcode to be run on the client.C /or the purpo!e! o' thi! boo9, you@ll !tic9 to dyn#*ic#lly gener#ting pl#in old nondyn#*ic >&3 .
5http://www.(ractalconcept.com/asp/html/mod=lisp.html 0http://lisplets.so'rce(orge.net/ 2%llegroSer?e
#l!o pro?ide! # 'r#*e6or9 c#lled Eebactions th#t@! #n#logou! to DSP! in the D#?# 6orld--in!te#d o' 6riting code th#t gener#te! >&3 , 6ith Web#ction! you 6rite p#ge! th#t #re e!!enti#lly >&3 6ith # bit o' *#gic 'oo th#t turn! into code to be run 6hen the p#ge i! !er?ed. I 6on@t co?er Web#ction! in thi! boo9.
,
o#ding Port#ble%llegroSer?e 6ill cre#te !o*e other p#c9#ge! 'or the co*p#tibility libr#rie!, but the p#c9#ge! you@ll c#re #bout #re tho!e three.
)&he
7P 'ollo6ed by # ne6line tell! FORMAT to ignore 6hite!p#ce #'ter the ne6line, 6hich #llo6! you to indent your code nicely 6ithout #dding # bunch o' 6hite!p#ce to the >&3 . Since 6hite-!p#ce i! typic#lly not !igni'ic#nt in >&3 , thi! doe!n@t *#tter to the bro6!er, but it *#9e! the gener#ted >&3
in'or*#tion #bout the *e#ning o' the other p#r#*eter!, !ee the %llegroSer?e docu*ent#tion #nd $/C 210), 6hich de!cribe! the coo9ie *ech#ni!*.
124ou
need to u!e LET* r#ther th#n # LET to #llo6 the de'#ult ?#lue 'or*! 'or p#r#*eter! to re'er to p#r#*eter! th#t #ppe#r e#rlier in the p#r#*eter li!t. /or e.#*ple, you could 6rite thi!:
1de(ine-'rl-('nction#1re@'est#1)#integer#0 3#1?#integer#1U#!#)333#...3
#nd the ?#lue o' ?, i' not e.plicitly !upplied, 6ould be t6ice the ?#lue o' ).
The 1ata2ase
&he *#in proble* 6ith the d#t#b#!e in Ch#pter 3 i! th#t there@! only one t#ble, the li!t !tored in the ?#ri#ble UdbU. %nother i! th#t the code doe!n@t 9no6 #nything #bout 6h#t type o' ?#lue! #re !tored in di''erent colu*n!. In Ch#pter 3 you got #6#y 6ith th#t by u!ing the '#irly gener#l-purpo!e EQUAL *ethod to co*p#re colu*n ?#lue! 6hen !electing ro6! 'ro* the d#t#b#!e, but you 6ould@?e been in trouble i' you h#d 6#nted to !tore ?#lue! th#t couldn@t be co*p#red 6ith EQUAL or i' you h#d 6#nted to !ort the ro6! in the d#t#b#!e !ince there@! no ordering 'unction th#t@! #! gener#l #! EQUAL. &hi! ti*e you@ll !ol?e both proble*! by de'ining # cl#!!, table, to repre!ent indi?idu#l d#t#b#!e t#ble!. (#ch table in!t#nce 6ill con!i!t o' t6o !lot!--one to hold the t#ble@! d#t# #nd #nother to hold in'or*#tion #bout the colu*n! in the t#ble th#t d#t#b#!e oper#tion! 6ill be #ble to u!e. &he cl#!! loo9! li9e thi!:
1de(class#table#13 ##11rows###:accessor#rows###:initarg#:rows#:init(orm#1ma&e-rows33 ###1schema#:accessor#schema#:initarg#:schema333
%! in Ch#pter 3, you c#n repre!ent the indi?idu#l ro6! 6ith pli!t!, but thi! ti*e #round you@ll cre#te #n #b!tr#ction th#t 6ill *#9e th#t #n i*ple*ent#tion det#il you c#n ch#nge l#ter 6ithout too *uch trouble. %nd thi! ti*e you@ll !tore the ro6! in # ?ector r#ther th#n # li!t !ince cert#in oper#tion! th#t you@ll 6#nt to !upport, !uch #! r#ndo* #cce!! to ro6! by # nu*eric inde. #nd the #bility to !ort # t#ble, c#n be *ore e''iciently i*ple*ented 6ith ?ector!. &he 'unction ma&e-rows u!ed to initi#liAe the rows !lot c#n be # !i*ple 6r#pper #round MA+EARRAY th#t build! #n e*pty, #d<u!t#ble,?ector 6ith # 'ill pointer.
&he P#c9#ge &he p#c9#ge 'or the code you@ll de?elop in thi! ch#pter loo9! li9e thi!:
1de(pac&age#:com.gigamon&e?s.mp3-database ##1:'se#:common-lisp# ########:com.gigamon&e?s.pathnames ########:com.gigamon&e?s.macro-'tilities ########:com.gigamon&e?s.id3v!3 ##1:e)port##:Ude(a'lt-table-si*eU ############:Ump3-schemaU ############:Ump3sU ############:col'mn ############:col'mn-val'e ############:delete-all-rows ############:delete-rows ############:do-rows ############:e)tract-schema ############:in ############:insert-row ############:load-database ############:ma&e-col'mn ############:ma&e-schema ############:map-rows ############:matching ############:not-n'llable ############:nth-row ############:random-selection ############:schema ############:select ############:sh'((le-table ############:sort-rows ############:table ############:table-si*e ############:with-col'mn-val'es33
&he :'se !ection gi?e! you #cce!! to the 'unction! #nd *#cro! 6ho!e n#*e! #re e.ported 'ro* the p#c9#ge! de'ined in Ch#pter 15, ,, #nd 25 #nd the :e)port !ection e.port! the %PI thi! libr#ry 6ill pro?ide, 6hich you@ll u!e in Ch#pter 2).
1de(parameter#Ude(a'lt-table-si*eU#0 3 1de('n#ma&e-rows#1>optional#1si*e#Ude(a'lt-table-si*eU33 ##1ma&e-arra?#si*e#:adj'stable#t#:(ill-pointer# 33
&o repre!ent # t#ble@! !che*#, you need to de'ine #nother cl#!!, col'mn, e#ch in!t#nce o' 6hich 6ill cont#in in'or*#tion #bout one colu*n in the t#ble: it! n#*e, ho6 to co*p#re ?#lue! in the colu*n 'or eFu#lity #nd ordering, # de'#ult ?#lue, #nd # 'unction th#t 6ill be u!ed to nor*#liAe the colu*n@! ?#lue! 6hen in!erting d#t# into the t#ble #nd 6hen Fuerying the t#ble. &he schema !lot 6ill hold # li!t o' col'mn ob<ect!. &he cl#!! de'inition loo9! li9e thi!:
1de(class#col'mn#13 ##11name############### ####:reader#name ####:initarg#:name3 ###1e@'alit?-predicate
####:reader#e@'alit?-predicate ####:initarg#:e@'alit?-predicate3 ###1comparator ####:reader#comparator ####:initarg#:comparator3 ###1de(a'lt-val'e ####:reader#de(a'lt-val'e ####:initarg#:de(a'lt-val'e ####:init(orm#nil3 ###1val'e-normali*er ####:reader#val'e-normali*er ####:initarg#:val'e-normali*er ####:init(orm#NC1lambda#1v#col'mn3#1declare#1ignore#col'mn33#v3333
&he e@'alit?-predicate #nd comparator !lot! o' # col'mn ob<ect hold 'unction! u!ed to co*p#re ?#lue! 'ro* the gi?en colu*n 'or eFui?#lence #nd ordering. &hu!, # colu*n cont#ining !tring ?#lue! *ight h#?e STRING= #! it! e@'alit?-predicate #nd STRING1 #! it! comparator, 6hile # colu*n cont#ining nu*ber! *ight h#?e = #nd 1. &he de(a'lt-val'e #nd val'e-normali*er !lot! #re u!ed 6hen in!erting ro6! into the d#t#b#!e #nd, in the c#!e o' val'e-normali*er, 6hen Fuerying the d#t#b#!e. When you in!ert # ro6 into the d#t#b#!e, i' no ?#lue i! pro?ided 'or # p#rticul#r colu*n, you c#n u!e the ?#lue !tored in the col'mn@! de(a'lt-val'e !lot. &hen the ?#lue--de'#ulted or other6i!e--i! nor*#liAed by p#!!ing it #nd the colu*n ob<ect to the 'unction !tored in the val'e-normali*er !lot. 4ou p#!! the colu*n in c#!e the val'e-normali*er 'unction need! to u!e !o*e d#t# #!!oci#ted 6ith the colu*n ob<ect. B4ou@ll !ee #n e.#*ple o' thi! in the ne.t !ection.C 4ou !hould #l!o nor*#liAe ?#lue! p#!!ed in Fuerie! be'ore co*p#ring the* 6ith ?#lue! in the d#t#b#!e. &hu!, the val'e-normali*er@! re!pon!ibility i! pri*#rily to return # ?#lue th#t c#n be !#'ely #nd correctly p#!!ed to the e@'alit?-predicate #nd comparator 'unction!. I' the val'enormali*er c#n@t 'igure out #n #ppropri#te ?#lue to return, it c#n !ign#l #n error. &he other re#!on to nor*#liAe ?#lue! be'ore you !tore the* in the d#t#b#!e i! to !#?e both *e*ory #nd CP8 cycle!. /or in!t#nce, i' you h#?e # colu*n th#t@! going to cont#in !tring ?#lue! but the nu*ber o' di!tinct !tring! th#t 6ill be !tored in the colu*n i! !*#ll--'or in!t#nce, the genre colu*n in the 3P3 d#t#b#!e--you c#n !#?e !p#ce #nd !peed by u!ing the val'e-normali*er to intern the !tring! Btr#n!l#te #ll STRING= ?#lue! to # !ingle !tring ob<ectC. &hu!, you@ll need only #! *#ny !tring! #! there #re di!tinct ?#lue!, reg#rdle!! o' ho6 *#ny ro6! #re in the t#ble, #nd you c#n u!e EQL to co*p#re colu*n ?#lue! r#ther th#n the !lo6er STRING=.1
1e ining a /che$a
&hu!, to *#9e #n in!t#nce o' table, you need to build # li!t o' col'mn ob<ect!. 4ou could build the li!t by h#nd, u!ing LIST #nd MA+E-INSTANCE. 7ut you@ll !oon notice th#t you@re 'reFuently *#9ing # lot colu*n ob<ect! 6ith the !#*e co*p#r#tor #nd eFu#lity-predic#te co*bin#tion!. &hi! i! bec#u!e the co*bin#tion o' # co*p#r#tor #nd eFu#lity predic#te e!!enti#lly de'ine! # colu*n type. It@d be nice i' there 6#! # 6#y to gi?e tho!e type! n#*e! th#t 6ould #llo6 you to !#y !i*ply th#t # gi?en colu*n i! # !tring colu*n, r#ther th#n h#?ing to !peci'y STRING1 #! it! co*p#r#tor #nd STRING= #! it! eFu#lity predic#te. 5ne 6#y i! to de'ine # generic 'unction, ma&e-col'mn, li9e thi!:
1de(generic#ma&e-col'mn#1name#t?pe#>optional#de(a'lt-val'e33
:o6 you c#n i*ple*ent *ethod! on thi! generic 'unction th#t !peci#liAe on t?pe 6ith EQL !peci#liAer! #nd return col'mn ob<ect! 6ith the !lot! 'illed in 6ith #ppropri#te ?#lue!. >ere@! the generic 'unction #nd *ethod! th#t de'ine colu*n type! 'or the type n#*e! string #nd n'mber:
1de(method#ma&e-col'mn#1name#1t?pe#1e@l#Cstring33#>optional#de(a'lt-val'e3 ##1ma&e-instance ###Ccol'mn# ###:name#name ###:comparator#NCstringO# ###:e@'alit?-predicate#NCstring= ###:de(a'lt-val'e#de(a'lt-val'e ###:val'e-normali*er#NCnot-n'llable33 1de(method#ma&e-col'mn#1name#1t?pe#1e@l#Cn'mber33#>optional#de(a'lt-val'e3 ##1ma&e-instance# ###Ccol'mn ###:name#name ###:comparator#NCO# ###:e@'alit?-predicate#NC= ###:de(a'lt-val'e#de(a'lt-val'e33
&he 'ollo6ing 'unction, not-n'llable, u!ed #! the val'e-normali*er 'or string colu*n!, !i*ply return! the ?#lue it@! gi?en unle!! the ?#lue i! NIL, in 6hich c#!e it !ign#l! #n error:
1de('n#not-n'llable#1val'e#col'mn3 ##1or#val'e#1error#4$ol'mn#7a#canCt#be#n'll4#1name#col'mn3333
&hi! i! i*port#nt bec#u!e STRING1 #nd STRING= 6ill !ign#l #n error i' c#lled on NILG it@! better to c#tch b#d ?#lue! be'ore they go into the t#ble r#ther th#n 6hen you try to u!e the*.2 %nother colu*n type you@ll need 'or the 3P3 d#t#b#!e i! #n interned-string 6ho!e ?#lue! #re interned #! di!cu!!ed pre?iou!ly. Since you need # h#!h t#ble in 6hich to intern ?#lue!, you !hould de'ine # !ubcl#!! o' col'mn, interned-val'es-col'mn, th#t #dd! # !lot 6ho!e ?#lue i! the h#!h t#ble you u!e to intern. &o i*ple*ent the #ctu#l interning, you@ll #l!o need to pro?ide #n :init(orm 'or val'enormali*er o' # 'unction th#t intern! the ?#lue in the colu*n@! interned-val'es h#!h t#ble. %nd bec#u!e one o' the *#in re#!on! to intern ?#lue! i! to #llo6 you to u!e EQL #! the eFu#lity predic#te, you !hould #l!o #dd #n :init(orm 'or the e@'alit?-predicate o' NCe@l.
1de(class#interned-val'es-col'mn#1col'mn3 ##11interned-val'es ####:reader#interned-val'es ####:init(orm#1ma&e-hash-table#:test#NCe@'al33 ###1e@'alit?-predicate#:init(orm#NCe@l3 ###1val'e-normali*er###:init(orm#NCintern-(or-col'mn333 1de('n#intern-(or-col'mn#1val'e#col'mn3 ##1let#11hash#1interned-val'es#col'mn333 ####1or#1gethash#1not-n'llable#val'e#col'mn3#hash3 ########1set(#1gethash#val'e#hash3#val'e3333
4ou c#n then de'ine # ma&e-col'mn *ethod !peci#liAed on the n#*e interned-string th#t return! #n in!t#nce o' interned-val'es-col'mn.
With the!e *ethod! de'ined on ma&e-col'mn, you c#n no6 de'ine # 'unction, ma&e-schema, th#t build! # li!t o' col'mn ob<ect! 'ro* # li!t o' colu*n !peci'ic#tion! con!i!ting o' # colu*n n#*e, # colu*n type n#*e, #nd, option#lly, # de'#ult ?#lue.
1de('n#ma&e-schema#1spec3 ##1mapcar#NC1lambda#1col'mn-spec3#1appl?#NCma&e-col'mn#col'mn-spec33#spec33
/or in!t#nce, you c#n de'ine the !che*# 'or the t#ble you@ll u!e to !tore d#t# e.tr#cted 'ro* 3P3! li9e thi!:
1de(parameter#Ump3-schemaU# ##1ma&e-schema# ###C11:(ile#####string3 #####1:genre####interned-string#4+n&nown43 #####1:artist###interned-string#4+n&nown43 #####1:alb'm####interned-string#4+n&nown43 #####1:song#####string3 #####1:trac&####n'mber# 3 #####1:?ear#####n'mber# 3 #####1:id3-si*e#n'mber3333
&o *#9e #n #ctu#l t#ble 'or holding in'or*#tion #bout 3P3!, you p#!! Ump3-schemaU #! the :schema init#rg to MA+E-INSTANCE.
1de(parameter#Ump3sU#1ma&e-instance#Ctable#:schema#Ump3-schemaU33
Inserting <a%ues
:o6 you@re re#dy to de'ine your 'ir!t t#ble oper#tion, insert-row, 6hich t#9e! # pli!t o' n#*e! #nd ?#lue! #nd # t#ble #nd #dd! # ro6 to the t#ble cont#ining the gi?en ?#lue!. &he bul9 o' the 6or9 i! done in # helper 'unction, normali*e-row, th#t build! # pli!t 6ith # de'#ulted, nor*#liAed ?#lue 'or e#ch colu*n, u!ing the ?#lue! 'ro* names-and-val'es i' #?#il#ble #nd the de(a'lt-val'e 'or the colu*n i' not.
1de('n#insert-row#1names-and-val'es#table3 ##1vector-p'sh-e)tend#1normali*e-row#names-and-val'es#1schema#table33#1rows# table333 1de('n#normali*e-row#1names-and-val'es#schema3 ##1loop #####(or#col'mn#in#schema #####(or#name##=#1name#col'mn3 #####(or#val'e#=#1or#1get(#names-and-val'es#name3#1de(a'lt-val'e#col'mn33 #####collect#name #####collect#1normali*e-(or-col'mn#val'e#col'mn333
It@! 6orth de'ining # !ep#r#te helper 'unction, normali*e-(or-col'mn, th#t t#9e! # ?#lue #nd #
col'mn ob<ect #nd return! the nor*#liAed ?#lue bec#u!e you@ll need to per'or* the !#*e nor*#liA#tion on Fuery #rgu*ent!.
1de('n#normali*e-(or-col'mn#1val'e#col'mn3 ##1('ncall#1val'e-normali*er#col'mn3#val'e#col'mn33
:o6 you@re re#dy to co*bine thi! d#t#b#!e code 6ith code 'ro* pre?iou! ch#pter! to build # d#t#b#!e o' d#t# e.tr#cted 'ro* 3P3 'ile!. 4ou c#n de'ine # 'unction, (ile-/row, th#t u!e! read-id3 'ro* the I+3?2 libr#ry to e.tr#ct #n I+3 t#g 'ro* # 'ile #nd turn! it into # pli!t th#t you c#n p#!! to insert-row.
1de('n#(ile-/row#1(ile3 ##1let#11id3#1read-id3#(ile333 ####1list #####:(ile###1namestring#1tr'ename#(ile33 #####:genre##1translated-genre#id33 #####:artist#1artist#id33 #####:alb'm##1alb'm#id33 #####:song###1song#id33 #####:trac&##1parse-tractrac&#id333 #####:?ear###1parse-?ear#1?ear#id333 #####:id3-si*e#1si*e#id33333
4ou don@t h#?e to 6orry #bout nor*#liAing the ?#lue! !ince insert-row t#9e! c#re o' th#t 'or you. 4ou do, ho6e?er, h#?e to con?ert the !tring ?#lue! returned by the trac& #nd ?ear into nu*ber!. &he tr#c9 nu*ber in #n I+3 t#g i! !o*eti*e! !tored #! the %SCII repre!ent#tion o' the tr#c9 nu*ber #nd !o*eti*e! #! # nu*ber 'ollo6ed by # !l#!h 'ollo6ed by the tot#l nu*ber o' tr#c9! on the #lbu*. Since you c#re only #bout the #ctu#l tr#c9 nu*ber, you !hould u!e the :end #rgu*ent to PARSEINTEGER to !peci'y th#t it !hould p#r!e only up to the !l#!h, i' #ny.3
1de('n#parse-tractrac&3 ##1when#tracparse-integer#trac&#:end#1position#NY/#trac&3333 1de('n#parse-?ear#1?ear3 ##1when#?ear#1parse-integer#?ear333
/in#lly, you c#n put #ll the!e 'unction! together, #long 6ith wal&-director? 'ro* the port#ble p#thn#*e! libr#ry #nd mp3-p 'ro* the I+3?2 libr#ry, to de'ine # 'unction th#t lo#d! #n 3P3 d#t#b#!e 6ith d#t# e.tr#cted 'ro* #ll the 3P3 'ile! it c#n 'ind under # gi?en directory.
1de('n#load-database#1dir#db3 ##1let#11co'nt# 33 ####1wal&-director?# #####dir# #####NC1lambda#1(ile3 #########1princ#NY.3 #########1inc(#co'nt3 #########1insert-row#1(ile-/row#(ile3#db33 #####:test#NCmp3-p3 ####1(ormat#t#47>Loaded#7d#(iles#into#database.4#co'nt333
you@ll need # !lightly *ore !ophi!tic#ted Fuery 'unction th#n you 6rote in Ch#pter 3. &hi! ti*e #round you 6#nt not only to be #ble to !elect ro6! *#tching p#rticul#r criteri# but #l!o to li*it the re!ult! to p#rticul#r colu*n!, to li*it the re!ult! to uniFue ro6!, #nd perh#p! to !ort the ro6! by p#rticul#r colu*n!. In 9eeping 6ith the !pirit o' rel#tion#l d#t#b#!e theory, the re!ult o' # Fuery 6ill be # ne6 table ob<ect cont#ining the de!ired ro6! #nd colu*n!. &he Fuery 'unction you@ll 6rite, select, i! loo!ely *odeled on the ,-L-$F !t#te*ent 'ro* Structured Muery #ngu#ge BSM C. It@ll t#9e 'i?e 9ey6ord p#r#*eter!: :(rom, :col'mns, :where, :distinct, #nd :order-b?. &he :(rom #rgu*ent i! the table ob<ect you 6#nt to Fuery. &he :col'mns #rgu*ent !peci'ie! 6hich colu*n! !hould be included in the re!ult. &he ?#lue !hould be # li!t o' colu*n n#*e!, # !ingle colu*n n#*e, or # T, the de'#ult, *e#ning return #ll colu*n!. &he :where #rgu*ent, i' pro?ided, !hould be # 'unction th#t #ccept! # ro6 #nd return! true i' it !hould be included in the re!ult!. In # *o*ent, you@ll 6rite t6o 'unction!, matching #nd in, th#t return 'unction! #ppropri#te 'or u!e #! :where #rgu*ent!. &he :order-b? #rgu*ent, i' !upplied, !hould be # li!t o' colu*n n#*e!G the re!ult! 6ill be !orted by the n#*ed colu*n!. %! 6ith the :col'mns #rgu*ent, you c#n !peci'y # !ingle colu*n u!ing <u!t the n#*e, 6hich i! eFui?#lent to # one-ite* li!t cont#ining the !#*e n#*e. /in#lly, the :distinct #rgu*ent i! # boole#n th#t !#y! 6hether to eli*in#te duplic#te ro6! 'ro* the re!ult!. &he de'#ult ?#lue 'or :distinct i! NIL. >ere #re !o*e e.#*ple! o' u!ing select:
SS#,elect#all#rows#where#the#:artist#col'mn#is#4Jreen#<a?4 1select#:(rom#Ump3sU#:where#1matching#Ump3sU#:artist#4Jreen#<a?433 SS#,elect#a#sorted#list#o(#artists#with#songs#in#the#genre#4.oc&4 1select ##:col'mns#:artist ##:(rom#Ump3sU ##:where#1matching#Ump3sU#:genre#4.oc&43 ##:distinct#t ##:order-b?#:artist3
&he i*ple*ent#tion o' select 6ith it! i**edi#te helper 'unction! loo9! li9e thi!:
1de('n#select#1>&e?#1col'mns#t3#(rom#where#distinct#order-b?3 ##1let#11rows#1rows#(rom33 ########1schema#1schema#(rom333 ####1when#where ######1set(#rows#1restrict-rows#rows#where333 ####1'nless#1e@l#col'mns#Ct3 ######1set(#schema#1e)tract-schema#1m&list#col'mns3#schema33 ######1set(#rows#1project-col'mns#rows#schema333 ####1when#distinct ######1set(#rows#1distinct-rows#rows#schema333 ####1when#order-b? ######1set(#rows#1sorted-rows#rows#schema#1m&list#order-b?3333 ####1ma&e-instance#Ctable#:rows#rows#:schema#schema333 1de('n#m&list#1thing3 ##1i(#1listp#thing3#thing#1list#thing333
1de('n#e)tract-schema#1col'mn-names#schema3 ##1loop#(or#c#in#col'mn-names#collect#1(ind-col'mn#c#schema333 1de('n#(ind-col'mn#1col'mn-name#schema3 ##1or#1(ind#col'mn-name#schema#:&e?#NCname3 ######1error#48o#col'mn:#7a#in#schema:#7a4#col'mn-name#schema333 1de('n#restrict-rows#1rows#where3 ##1remove-i(-not#where#rows33 1de('n#project-col'mns#1rows#schema3 ##1map#Cvector#1e)tractor#schema3#rows33 1de('n#distinct-rows#1rows#schema3 ##1remove-d'plicates#rows#:test#1row-e@'alit?-tester#schema333 1de('n#sorted-rows#1rows#schema#order-b?3 ##1sort#1cop?-se@#rows3#1row-comparator#order-b?#schema333
5' cour!e, the re#lly intere!ting p#rt o' select i! ho6 you i*ple*ent the 'unction! e)tractor, row-e@'alit?-tester, #nd row-comparator. %! you c#n tell by ho6 they@re u!ed, e#ch o' the!e 'unction! *u!t return # 'unction. /or in!t#nce, project-col'mns u!e! the ?#lue returned by e)tractor #! the 'unction #rgu*ent to MAP. Since the purpo!e o' project-col'mns i! to return # !et o' ro6! 6ith only cert#in colu*n ?#lue!, you c#n in'er th#t e)tractor return! # 'unction th#t t#9e! # ro6 #! #n #rgu*ent #nd return! # ne6 ro6 cont#ining only the colu*n! !peci'ied in the !che*# it@! p#!!ed. >ere@! ho6 you c#n i*ple*ent it:
1de('n#e)tractor#1schema3 ##1let#11names#1mapcar#NCname#schema333 ####NC1lambda#1row3 ########1loop#(or#c#in#names#collect#c#collect#1get(#row#c33333
:ote ho6 you c#n do the 6or9 o' e.tr#cting the n#*e! 'ro* the !che*# out!ide the body o' the clo!ure: !ince the clo!ure 6ill be c#lled *#ny ti*e!, you 6#nt it to do #! little 6or9 #! po!!ible e#ch ti*e it@! c#lled. &he 'unction! row-e@'alit?-tester #nd row-comparator #re i*ple*ented in # !i*il#r 6#y. &o decide 6hether t6o ro6! #re eFui?#lent, you need to #pply the #ppropri#te eFu#lity predic#te 'or e#ch colu*n to the #ppropri#te colu*n ?#lue!. $ec#ll 'ro* Ch#pter 22 th#t the LOOP cl#u!e alwa?s 6ill return NIL #! !oon #! # p#ir o' ?#lue! '#il! their te!t or 6ill c#u!e the LOOP to return T.
1de('n#row-e@'alit?-tester#1schema3 ##1let#11names#1mapcar#NCname#schema33 ########1tests#1mapcar#NCe@'alit?-predicate#schema333 ####NC1lambda#1a#b3 ########1loop#(or#name#in#names#and#test#in#tests ###########alwa?s#1('ncall#test#1get(#a#name3#1get(#b#name333333
5rdering t6o ro6! i! # bit *ore co*ple.. In i!p, co*p#r#tor 'unction! return true i' their 'ir!t #rgu*ent !hould be !orted #he#d o' the !econd #nd NIL other6i!e. &hu!, # NIL c#n *e#n th#t the !econd #rgu*ent !hould be !orted #he#d o' the 'ir!t or th#t they@re eFui?#lent. 4ou 6#nt your ro6 co*p#r#tor! to beh#?e the !#*e 6#y: return T i' the 'ir!t ro6 !hould be !orted #he#d o' the !econd #nd NIL other6i!e. &hu!, to co*p#re t6o ro6!, you !hould co*p#re the ?#lue! 'ro* the colu*n! you@re !orting by, in
order, u!ing the #ppropri#te co*p#r#tor 'or e#ch colu*n. /ir!t c#ll the co*p#r#tor 6ith the ?#lue 'ro* the 'ir!t ro6 #! the 'ir!t #rgu*ent. I' the co*p#r#tor return! true, th#t *e#n! the 'ir!t ro6 !hould de'initely be !orted #he#d o' the !econd ro6, !o you c#n i**edi#tely return T. 7ut i' the colu*n co*p#r#tor return! NIL, then you need to deter*ine 6hether th#t@! bec#u!e the !econd ?#lue !hould !ort #he#d o' the 'ir!t ?#lue or bec#u!e they@re eFui?#lent. So you !hould c#ll the co*p#r#tor #g#in 6ith the #rgu*ent! re?er!ed. I' the co*p#r#tor return! true thi! ti*e, it *e#n! the !econd colu*n ?#lue !ort! #he#d o' the 'ir!t #nd thu! the !econd ro6 #he#d o' the 'ir!t ro6, !o you c#n return NIL i**edi#tely. 5ther6i!e, the colu*n ?#lue! #re eFui?#lent, #nd you need to *o?e onto the ne.t colu*n. I' you get through #ll the colu*n! 6ithout one ro6@! ?#lue e?er 6inning the co*p#ri!on, then the ro6! #re eFui?#lent, #nd you return NIL. % 'unction th#t i*ple*ent! thi! #lgorith* loo9! li9e thi!:
1de('n#row-comparator#1col'mn-names#schema3 ##1let#11comparators#1mapcar#NCcomparator#1e)tract-schema#col'mn-names#schema3333 ####NC1lambda#1a#b3 ########1loop ###########(or#name#in#col'mn-names ###########(or#comparator#in#comparators ###########(or#a-val'e#=#1get(#a#name3 ###########(or#b-val'e#=#1get(#b#name3 ###########when#1('ncall#comparator#a-val'e#b-val'e3#ret'rn#t ###########when#1('ncall#comparator#b-val'e#a-val'e3#ret'rn#nil ###########(inall?#1ret'rn#nil33333
+atching Functions
&he :where #rgu*ent to select c#n be #ny 'unction th#t t#9e! # ro6 ob<ect #nd return! true i' it !hould be included in the re!ult!. In pr#ctice, ho6e?er, you@ll r#rely need the 'ull po6er o' #rbitr#ry code to e.pre!! Fuery criteri#. So you !hould pro?ide t6o 'unction!, matching #nd in, th#t 6ill build Fuery 'unction! th#t #llo6 you to e.pre!! the co**on 9ind! o' Fuerie! #nd th#t t#9e c#re o' u!ing the proper eFu#lity predic#te! #nd ?#lue nor*#liAer! 'or e#ch colu*n. &he 6or9hou!e Fuery-'unction con!tructor 6ill be matching, 6hich return! # 'unction th#t 6ill *#tch ro6! 6ith !peci'ic colu*n ?#lue!. 4ou !#6 ho6 it 6#! u!ed in the e#rlier e.#*ple! o' select. /or in!t#nce, thi! c#ll to matching:
1matching#Ump3sU#:artist#4Jreen#<a?43
return! # 'unction th#t *#tche! ro6! 6ho!e :artist ?#lue i! H=reen +#yH. 4ou c#n #l!o p#!! *ultiple n#*e! #nd ?#lue!G the returned 'unction *#tche! 6hen #ll the colu*n! *#tch. /or e.#*ple, the 'ollo6ing return! # clo!ure th#t *#tche! ro6! 6here the #rti!t i! H=reen +#yH #nd the #lbu* i! H%*eric#n IdiotH:
1matching#Ump3sU#:artist#4Jreen#<a?4#:alb'm#4Imerican#9diot43
4ou h#?e to p#!! matching the t#ble ob<ect bec#u!e it need! #cce!! to the t#ble@! !che*# in order to get #t the eFu#lity predic#te! #nd ?#lue nor*#liAer 'unction! 'or the colu*n! it *#tche! #g#in!t. 4ou build up the 'unction returned by matching out o' !*#ller 'unction!, e#ch re!pon!ible 'or *#tching one colu*n@! ?#lue. &o build the!e 'unction!, you !hould de'ine # 'unction, col'mnmatcher, th#t t#9e! # col'mn ob<ect #nd #n unnor*#liAed ?#lue you 6#nt to *#tch #nd return! # 'unction th#t #ccept! # !ingle ro6 #nd return! true 6hen the ?#lue o' the gi?en colu*n in the ro6
4ou then build # li!t o' colu*n-*#tching 'unction! 'or the n#*e! #nd ?#lue! you c#re #bout 6ith the 'ollo6ing 'unction, col'mn-matchers:
1de('n#col'mn-matchers#1schema#names-and-val'es3 ##1loop#(or#1name#val'e3#on#names-and-val'es#b?#NCcddr #####when#val'e#collect #######1col'mn-matcher#1(ind-col'mn#name#schema3#val'e333
:o6 you c#n i*ple*ent matching. %g#in, note th#t you do #! *uch 6or9 #! po!!ible out!ide the clo!ure in order to do it only once r#ther th#n once per ro6 in the t#ble.
1de('n#matching#1table#>rest#names-and-val'es3 ##4L'ild#a#where#('nction#that#matches#rows#with#the#given#col'mn#val'es.4 ##1let#11matchers#1col'mn-matchers#1schema#table3#names-and-val'es333 ####NC1lambda#1row3 ########1ever?#NC1lambda#1matcher3#1('ncall#matcher#row33#matchers3333
&hi! 'unction i! # bit o' # t6i!ty *#Ae o' clo!ure!, but it@! 6orth conte*pl#ting 'or # *o*ent to get # 'l#?or o' the po!!ibilitie! o' progr#**ing 6ith 'unction! #! 'ir!t-cl#!! ob<ect!. &he <ob o' matching i! to return # 'unction th#t 6ill be in?o9ed on e#ch ro6 in # t#ble to deter*ine 6hether it !hould be included in the ne6 t#ble. So, matching return! # clo!ure 6ith one p#r#*eter, row. :o6 rec#ll th#t the 'unction EVERY t#9e! # predic#te 'unction #! it! 'ir!t #rgu*ent #nd return! true i', #nd only i', th#t 'unction return! true e#ch ti*e it@! #pplied to #n ele*ent o' the li!t p#!!ed #! EVERY@! !econd #rgu*ent. >o6e?er, in thi! c#!e, the li!t you p#!! to EVERY i! it!el' # li!t o' 'unction!, the colu*n *#tcher!. Wh#t you 6#nt to 9no6 i! th#t e?ery colu*n *#tcher, 6hen in?o9ed on the ro6 you@re currently te!ting, return! true. So, #! the predic#te #rgu*ent to EVERY, you p#!! yet #nother clo!ure th#t FUNCALL! the colu*n *#tcher, p#!!ing it the ro6. %nother *#tching 'unction th#t you@ll occ#!ion#lly 'ind u!e'ul i! in, 6hich return! # 'unction th#t *#tche! ro6! 6here # p#rticul#r colu*n i! in # gi?en !et o' ?#lue!. 4ou@ll de'ine in to t#9e t6o #rgu*ent!: # colu*n n#*e #nd # t#ble th#t cont#in! the ?#lue! you 6#nt to *#tch. /or in!t#nce, !uppo!e you 6#nted to 'ind #ll the !ong! in the 3P3 d#t#b#!e th#t h#?e n#*e! the !#*e #! # !ong per'or*ed by the +i.ie Chic9!. 4ou c#n 6rite th#t 6here cl#u!e u!ing in #nd # !ubselect li9e thi!:1select ##:col'mns#C1:artist#:song3 ##:(rom#Ump3sU ##:where#1in#:song# #############1select ###############:col'mns#:song ###############:(rom#Ump3sU ###############:where#1matching#Ump3sU#:artist#4<i)ie#$hic&s43333
%lthough the Fuerie! #re *ore co*ple., the de'inition o' in i! *uch !i*pler th#n th#t o' matching.
&o get #t indi?idu#l colu*n ?#lue! 6ithin # ro6, you !hould pro?ide # 'unction, col'mn-val'e, th#t t#9e! # ro6 #nd # colu*n n#*e #nd return! the #ppropri#te ?#lue. %g#in, it@! # tri?i#l 6r#pper #round the code you@d 6rite other6i!e. 7ut i' you ch#nge the intern#l repre!ent#tion o' # t#ble l#ter, u!er! o' col'mn-val'e needn@t be #ny the 6i!er.
1de('n#col'mn-val'e#1row#col'mn-name3 ##1get(#row#col'mn-name33
While col'mn-val'e i! # !u''icient #b!tr#ction 'or getting #t colu*n ?#lue!, you@ll o'ten 6#nt to get #t the ?#lue! o' *ultiple colu*n! #t once. So you c#n pro?ide # bit o' !ynt#ctic !ug#r, # *#cro, withcol'mn-val'es, th#t bind! # !et o' ?#ri#ble! to the ?#lue! e.tr#cted 'ro* # ro6 u!ing the corre!ponding 9ey6ord n#*e!. &hu!, in!te#d o' 6riting thi!:
#1do-rows#1row#table3 ###1let#11song#1col'mn-val'e#row#:song33 #########1artist#1col'mn-val'e#row#:artist33
#########1alb'm#1col'mn-val'e#row#:alb'm333 #####1(ormat#t#47a#b?#7a#(rom#7a764#song#artist#alb'm333
%g#in, the #ctu#l i*ple*ent#tion i!n@t co*plic#ted i' you u!e the once-onl? *#cro 'ro* Ch#pter ,.
1de(macro#with-col'mn-val'es#11>rest#vars3#row#>bod?#bod?3 ##1once-onl?#1row3 ####B1let#51col'mn-bindings#vars#row3#5Pbod?333 1de('n#col'mn-bindings#1vars#row3 ##1loop#(or#v#in#vars#collect#B15v#1col'mn-val'e#5row#51as-&e?word#v33333 1de('n#as-&e?word#1s?mbol3 ##1intern#1s?mbol-name#s?mbol3#:&e?word33
/in#lly, you !hould pro?ide #b!tr#ction! 'or getting #t the nu*ber o' ro6! in # t#ble #nd 'or #cce!!ing # !peci'ic ro6 by nu*eric inde..
1de('n#table-si*e#1table3 ##1length#1rows#table333 1de('n#nth-row#1n#table3 ##1are(#1rows#table3#n33
In the intere!t o' e''iciency, you *ight 6#nt to pro?ide # !ep#r#te 'unction 'or deleting #ll the ro6! 'ro* # t#ble.
1de('n#delete-all-rows#1table3 ##1set(#1rows#table3#1ma&e-rows#Ude(a'lt-table-si*eU333
&he re*#ining t#ble oper#tion! don@t re#lly *#p to nor*#l rel#tion#l d#t#b#!e oper#tion! but 6ill be u!e'ul in the 3P3 bro6!er #pplic#tion. &he 'ir!t i! # 'unction to !ort the ro6! o' # t#ble in pl#ce.
1de('n#sort-rows#1table#>rest#col'mn-names3 ##1set(#1rows#table3#1sort#1rows#table3#1row-comparator#col'mn-names#1schema# table3333 ##table3
5n the 'lip !ide, in the 3P3 bro6!er #pplic#tion, you@ll need # 'unction th#t !hu''le! # t#ble@! ro6! in pl#ce u!ing the 'unction nsh'((le-vector 'ro* Ch#pter 23.
1de('n#sh'((le-table#1table3 ##1nsh'((le-vector#1rows#table33 ##table3
%nd 'in#lly, #g#in 'or the purpo!e! o' the 3P3 bro6!er, you !hould pro?ide # 'unction th#t !elect! n r#ndo* ro6!, returning the re!ult! #! # ne6 t#ble. It #l!o u!e! nsh'((le-vector #long 6ith # ?er!ion o' random-sample b#!ed on %lgorith* S 'ro* +on#ld Lnuth@! The !rt of Computer Programming< ?olume 5: -eminumerical !lgorithms, &hird (dition B%ddi!on-We!ley, 1)),C th#t I di!cu!!ed in Ch#pter 20.
1de('n#random-selection#1table#n3 ##1ma&e-instance ###Ctable ###:schema#1schema#table3 ###:rows#1nsh'((le-vector#1random-sample#1rows#table3#n3333 1de('n#random-sample#1vector#n3 ##4Lased#on#Ilgorithm#,#(rom#Mn'th.#FI;$T5#vol.#!.#p.#04!4 ##1loop#with#selected#=#1ma&e-arra?#n#:(ill-pointer# 3 #####(or#id)#(rom# #####do #######1loop ##########with#to-select#=#1-#n#1length#selected33 ##########(or#remaining#=#1-#1length#vector3#id)3 ##########while#1/=#1U#remaining#1random#0. 33#to-select3 ##########do#1inc(#id)33 #######1vector-p'sh#1are(#vector#id)3#selected3 #####when#1=#1length#selected3#n3#ret'rn#selected33
With thi! code you@ll be re#dy, in Ch#pter 2), to build # Web inter'#ce 'or bro6!ing # collection o' 3P3 'ile!. 7ut be'ore you get to th#t, you need to i*ple*ent the p#rt o' the !er?er th#t !tre#*! 3P3! u!ing the Shoutc#!t protocol, 6hich i! the topic o' the ne.t ch#pter.
1&he
gener#l theory behind interning ob<ect! i! th#t i' you@re going to co*p#re # p#rticul#r ?#lue *#ny ti*e!, it@! 6orth it to p#y the co!t o' interning it. &he val'e-normali*er run! once 6hen you in!ert # ?#lue into the t#ble #nd, #! you@ll !ee, once #t the beginning o' e#ch Fuery. Since # Fuery c#n in?ol?e in?o9ing the e@'alit?-predicate once per ro6 in the t#ble, the #*ortiAed co!t o' interning the ?#lue! 6ill Fuic9ly #ppro#ch Aero.
2%!
#l6#y!, the 'ir!t c#u!#lity o' conci!e e.po!ition in progr#**ing boo9! i! proper error h#ndlingG in production code you@d prob#bly 6#nt to de'ine your o6n error type, !uch #! the 'ollo6ing, #nd !ign#l it in!te#d:
1error#Cillegal-col'mn-val'e#:val'e#val'e#:col'mn#col'mn3
&hen you@d 6#nt to thin9 #bout 6here you c#n #dd re!t#rt! th#t *ight be #ble to reco?er 'ro* thi! condition. %nd, 'in#lly, in #ny gi?en #pplic#tion you could e!t#bli!h condition h#ndler! th#t 6ould choo!e 'ro* #*ong tho!e re!t#rt!.
3I'
#ny 3P3 'ile! h#?e *#l'or*ed d#t# in the tr#c9 #nd ye#r 'r#*e!, PARSE-INTEGER could !ign#l #n error. 5ne 6#y to de#l 6ith th#t i! to p#!! PARSE-INTEGER the :j'n&-allowed #rgu*ent o' T, 6hich 6ill c#u!e it to ignore #ny non-nu*eric <un9 'ollo6ing the nu*ber #nd to return NIL i' no nu*ber c#n be 'ound in the !tring. 5r, i' you 6#nt pr#ctice #t u!ing the condition !y!te*, you could de'ine #n error #nd !ign#l it 'ro* the!e 'unction! 6hen the d#t# i! *#l'or*ed #nd #l!o e!t#bli!h # 'e6 re!t#rt! to #llo6 the!e 'unction! to reco?er.
-&hi!
Fuery 6ill #l!o return #ll the !ong! per'or*ed by the +i.ie Chic9!. I' you 6#nt to li*it it to !ong! by #rti!t! other th#n the +i.ie Chic9!, you need # *ore co*ple. :where 'unction. Since the :where #rgu*ent c#n be #ny 'unction, it@! cert#inly po!!ibleG you could re*o?e the +i.ie Chic9!@ o6n !ong! 6ith thi! Fuery:
1letU#11di)ie-chic&s#1matching#Ump3sU#:artist#4<i)ie#$hic&s433 #######1same-song#1in#:song#1select#:col'mns#:song#:(rom#Ump3sU#:where#di)iechic&s333 #######1@'er?#NC1lambda#1row3#1and#1not#1('ncall#di)ie-chic&s#row33#1('ncall#samesong#row33333 ##1select#:col'mns#C1:artist#:song3#:(rom#Ump3sU#:where#@'er?33
&hi! ob?iou!ly i!n@t Fuite #! con?enient. I' you 6ere going to 6rite #n #pplic#tion th#t needed to do lot! o' co*ple. Fuerie!, you *ight 6#nt to con!ider co*ing up 6ith # *ore e.pre!!i?e Fuery l#ngu#ge.
5&he
?er!ion o' LOOP i*ple*ented #t 3.I.&. be'ore Co**on i!p 6#! !t#nd#rdiAed included # *ech#ni!* 'or e.tending the LOOP gr#**#r to !upport iter#tion o?er ne6 d#t# !tructure!. So*e Co**on i!p i*ple*ent#tion! th#t inherited their LOOP i*ple*ent#tion 'ro* th#t code b#!e *#y !till !upport th#t '#cility, 6hich 6ould *#9e do-rows #nd map-rows le!! nece!!#ry.
&heir !che*e 6#! to !i*ply ignore the !tructure o' 3P3 d#t# #nd e*bed # chun9 o' !el'-deli*iting *et#d#t# e?ery n byte!. &he client 6ould then be re!pon!ible 'or !tripping out thi! *et#d#t# !o it 6#!n@t tre#ted #! 3P3 d#t#. Since *et#d#t# !ent to # client th#t i!n@t re#dy 'or it 6ill c#u!e glitche! in the !ound, the !er?er i! !uppo!ed to !end *et#d#t# only i' the client@! origin#l reFue!t cont#in! # !peci#l Icy-3et#d#t# he#der. %nd in order 'or the client to 9no6 ho6 o'ten to e.pect *et#d#t#, the !er?er *u!t !end b#c9 # he#der Icy-3et#int 6ho!e ?#lue i! the nu*ber o' byte! o' 3P3 d#t# th#t 6ill be !ent bet6een e#ch chun9 o' *et#d#t#. &he b#!ic content o' the *et#d#t# i! # !tring o' the 'or* HStre#*&itleU@title@GH 6here title i! the title o' the current !ong #nd c#n@t cont#in !ingle Fuote *#r9!. &hi! p#ylo#d i! encoded #! # length-deli*ited #rr#y o' byte!: # !ingle byte i! !ent indic#ting ho6 *#ny 10-byte bloc9! 'ollo6, #nd then th#t *#ny bloc9! #re !ent. &hey cont#in the !tring p#ylo#d #! #n %SCII !tring, 6ith the 'in#l bloc9 p#dded out 6ith null byte! #! nece!!#ry. &hu!, the !*#lle!t leg#l *et#d#t# chun9 i! # !ingle byte, Aero, indic#ting Aero !ub!eFuent bloc9!. I' the !er?er doe!n@t need to upd#te the *et#d#t#, it c#n !end !uch #n e*pty chun9, but it *u!t !end #t le#!t the one byte !o the client doe!n@t thro6 #6#y #ctu#l 3P3 d#t#.
/ong /ources
7ec#u!e # Shoutc#!t !er?er h#! to 9eep !tre#*ing !ong! to the client 'or #! long #! it@! connected, you need to pro?ide your !er?er 6ith # !ource o' !ong! to dr#6 on. In the Web-b#!ed #pplic#tion, e#ch connected client 6ill h#?e # pl#yli!t th#t c#n be *#nipul#ted ?i# the Web inter'#ce. 7ut in the intere!t o' #?oiding e.ce!!i?e coupling, you !hould de'ine #n inter'#ce th#t the Shoutc#!t !er?er c#n u!e to obt#in !ong! to pl#y. 4ou c#n 6rite # !i*ple i*ple*ent#tion o' thi! inter'#ce no6 #nd then # *ore co*ple. one #! p#rt o' the Web #pplic#tion you@ll build in Ch#pter 2). &he P#c9#ge &he p#c9#ge 'or the code you@ll de?elop in thi! ch#pter loo9! li9e thi!:
1de(pac&age#:com.gigamon&e?s.sho'tcast ##1:'se#:common-lisp# ########:net.aserve# ########:com.gigamon&e?s.id3v!3 ##1:e)port#:song ###########:(ile ###########:title ###########:id3-si*e ###########:(ind-song-so'rce ###########:c'rrent-song ###########:still-c'rrent-p ###########:ma?be-move-to-ne)t-song ###########:Usong-so'rce-t?peU33
&he ide# behind the inter'#ce i! th#t the Shoutc#!t !er?er 6ill 'ind # !ource o' !ong! b#!ed on #n I+ e.tr#cted 'ro* the %llegroSer?e reFue!t ob<ect. It c#n then do three thing! 6ith the !ong !ource it@! gi?en. =et the current !ong 'ro* the !ource &ell the !ong !ource th#t it@! done 6ith the current !ong %!9 the !ource 6hether the !ong it 6#! gi?en e#rlier i! !till the current !ong &he l#!t oper#tion i! nece!!#ry bec#u!e there *#y be 6#y!--#nd 6ill be in Ch#pter 2)--to *#nipul#te
the !ong! !ource out!ide the Shoutc#!t !er?er. 4ou c#n e.pre!! the oper#tion! the Shoutc#!t !er?er need! 6ith the 'ollo6ing generic 'unction!:
1de(generic#c'rrent-song#1so'rce3 ##1:doc'mentation#4.et'rn#the#c'rrentl?#pla?ing#song#or#89L.433 1de(generic#ma?be-move-to-ne)t-song#1song#so'rce3 ##1:doc'mentation ###49(#the#given#song#is#still#the#c'rrent#one#'pdate#the#val'e ret'rned#b?#c'rrent-song.433 1de(generic#still-c'rrent-p#1song#so'rce3 ##1:doc'mentation ###4.et'rn#tr'e#i(#the#song#given#is#the#same#as#the#c'rrent-song.433
&he 'unction ma?be-move-to-ne)t-song i! de'ined the 6#y it i! !o # !ingle oper#tion chec9! 6hether the !ong i! current #nd, i' it i!, *o?e! the !ong !ource to the ne.t !ong. &hi! 6ill be i*port#nt in the ne.t ch#pter 6hen you need to i*ple*ent # !ong !ource th#t c#n be !#'ely *#nipul#ted 'ro* t6o di''erent thre#d!.3 &o repre!ent the in'or*#tion #bout # !ong th#t the Shoutc#!t !er?er need!, you c#n de'ine # cl#!!, song, 6ith !lot! to hold the n#*e o' the 3P3 'ile, the title to !end in the Shoutc#!t *et#d#t#, #nd the !iAe o' the I+3 t#g !o you c#n !9ip it 6hen !er?ing up the 'ile.
1de(class#song#13 ##11(ile#####:reader#(ile#####:initarg#:(ile3 ###1title####:reader#title####:initarg#:title3 ###1id3-si*e#:reader#id3-si*e#:initarg#:id3-si*e333
&he ?#lue returned by c'rrent-song B#nd thu! the 'ir!t #rgu*ent to still-c'rrent-p #nd ma?be-move-to-ne)t-songC 6ill be #n in!t#nce o' song. In #ddition, you need to de'ine # generic 'unction th#t the !er?er c#n u!e to 'ind # !ong !ource b#!ed on the type o' !ource de!ired #nd the reFue!t ob<ect. 3ethod! 6ill !peci#liAe the t?pe p#r#*eter in order to return di''erent 9ind! o' !ong !ource #nd 6ill pull 6h#te?er in'or*#tion they need 'ro* the reFue!t ob<ect to deter*ine 6hich !ource to return.
1de(generic#(ind-song-so'rce#1t?pe#re@'est3 ##1:doc'mentation#4Eind#the#song-so'rce#o(#the#given#t?pe#(or#the#given# re@'est.433
>o6e?er, 'or the purpo!e! o' thi! ch#pter, you c#n u!e # tri?i#l i*ple*ent#tion o' thi! inter'#ce th#t #l6#y! u!e! the !#*e ob<ect, # !i*ple Fueue o' !ong ob<ect! th#t you c#n *#nipul#te 'ro* the $(P . 4ou c#n !t#rt by de'ining # cl#!!, simple-song-@'e'e, #nd # glob#l ?#ri#ble, UsongsU, th#t hold! #n in!t#nce o' thi! cl#!!.
1de(class#simple-song-@'e'e#13 ##11songs#:accessor#songs#:init(orm#1ma&e-arra?#0 #:adj'stable#t#:(ill-pointer# 33 ###1inde)#:accessor#inde)#:init(orm# 333 1de(parameter#UsongsU#1ma&e-instance#Csimple-song-@'e'e33
&hen you c#n de'ine # *ethod on (ind-song-so'rce th#t !peci#liAe! t?pe 6ith #n EQL !peci#liAer on the !y*bol singleton #nd return! the in!t#nce !tored in UsongsU.
1de(method#(ind-song-so'rce#11t?pe#1e@l#Csingleton33#re@'est3
##1declare#1ignore#re@'est33 ##UsongsU3
:o6 you <u!t need to i*ple*ent *ethod! on the three generic 'unction! th#t the Shoutc#!t !er?er 6ill u!e.
1de(method#c'rrent-song#11so'rce#simple-song-@'e'e33 ##1when#1arra?-in-bo'nds-p#1songs#so'rce3#1inde)#so'rce33 ####1are(#1songs#so'rce3#1inde)#so'rce3333 1de(method#still-c'rrent-p#1song#1so'rce#simple-song-@'e'e33 ##1e@l#song#1c'rrent-song#so'rce333 1de(method#ma?be-move-to-ne)t-song#1song#1so'rce#simple-song-@'e'e33 ##1when#1still-c'rrent-p#song#so'rce3 ####1inc(#1inde)#so'rce3333
%nd 'or te!ting purpo!e! you !hould pro?ide # 6#y to #dd !ong! to thi! Fueue.
1de('n#add-(ile-to-songs#1(ile3 ##1vector-p'sh-e)tend#1(ile-/song#(ile3#1songs#UsongsU333 1de('n#(ile-/song#1(ile3 ##1let#11id3#1read-id3#(ile333 ####1ma&e-instance# #####Csong #####:(ile#1namestring#1tr'ename#(ile33 #####:title#1(ormat#nil#47a#b?#7a#(rom#7a4#1song#id33#1artist#id33#1alb'm#id333 #####:id3-si*e#1si*e#id33333
I$p%e$enting /houtcast
:o6 you@re re#dy to i*ple*ent the Shoutc#!t !er?er. Since the Shoutc#!t protocol i! loo!ely b#!ed on >&&P, you c#n i*ple*ent the !er?er #! # 'unction 6ithin %llegroSer?e. >o6e?er, !ince you need to inter#ct 6ith !o*e o' the lo6-le?el 'e#ture! o' %llegroSer?e, you c#n@t u!e the de(ine-'rl('nction *#cro 'ro* Ch#pter 20. In!te#d, you need to 6rite # regul#r 'unction th#t loo9! li9e thi!:
1de('n#sho'tcast#1re@'est#entit?3 ##1with-http-response ######1re@'est#entit?#:content-t?pe#4a'dio/%T34#:timeo't#Utimeo't-secondsU3 ####1prepare-ic?-response#re@'est#Umetadata-intervalU3 ####1let#11wants-metadata-p#1header-slot-val'e#re@'est#:ic?-metadata333 ######1with-http-bod?#1re@'est#entit?3 ########1pla?-songs# #########1re@'est-soc&et#re@'est3 #########1(ind-song-so'rce#Usong-so'rce-t?peU#re@'est3 #########1i(#wants-metadata-p#Umetadata-intervalU333333
&hen publi!h th#t 'unction under the p#th /stream.mp3 li9e thi!:1p'blish#:path#4/stream.mp34#:('nction#Csho'tcast3
In the c#ll to with-http-response, in #ddition to the u!u#l re@'est #nd entit? #rgu*ent!, you need to p#!! :content-t?pe #nd :timeo't #rgu*ent!. &he :content-t?pe #rgu*ent tell! %llegroSer?e ho6 to !et the Content-&ype he#der it !end!. %nd the :timeo't #rgu*ent !peci'ie!
the nu*ber o' !econd! %llegroSer?e gi?e! the 'unction to gener#te it! re!pon!e. 7y de'#ult %llegroSer?e ti*e! out e#ch reFue!t #'ter 'i?e *inute!. 7ec#u!e you@re going to !tre#* #n e!!enti#lly endle!! !eFuence o' 3P3!, you need *uch *ore ti*e. &here@! no 6#y to tell %llegroSer?e to never ti*e out the reFue!t, !o you !hould !et it to the ?#lue o' Utimeo't-secondsU, 6hich you c#n de'ine to !o*e !uit#bly l#rge ?#lue !uch #! the nu*ber o' !econd! in ten ye#r!.
1de(parameter#Utimeo't-secondsU#1U#6 #6 #!4#Q#"!#0 33
&hen, 6ithin the body o' the with-http-response #nd be'ore the c#ll to with-http-bod? th#t 6ill c#u!e the re!pon!e he#der! to be !ent, you need to *#nipul#te the reply th#t %llegroSer?e 6ill !end. &he 'unction prepare-ic?-response enc#p!ul#te! the nece!!#ry *#nipul#tion!: ch#nging the protocol !tring 'ro* the de'#ult o' H>&&PH to HIC4H #nd #dding the Shoutc#!t-!peci'ic he#der!.5 4ou #l!o need, in order to 6or9 #round # bug in i&une!, to tell %llegroSer?e not to u!e chun$ed transfer)encoding.0 &he 'unction! re@'est-repl?-protocol-string, re@'est-'ri, #nd repl?-header-slot-val'e #re #ll p#rt o' %llegroSer?e.
1de('n#prepare-ic?-response#1re@'est#metadata-interval3 ##1set(#1re@'est-repl?-protocol-string#re@'est3#49$H43 ##1loop#(or#1&#v3#in#1reverse #######B11:Xic?-metaintX#51princ-to-string#metadata-interval33 #########1:Xic?-notice0X#4OL./Fhis#stream#blah#blah#blahOL./43 #########1:Xic?-notice!X#4%ore#blah43 #########1:Xic?-nameX####4%?Lisp,ho'tcast,erver43 #########1:Xic?-genreX###4+n&nown43 #########1:Xic?-'rlX#####51re@'est-'ri#re@'est33 #########1:Xic?-p'bX#####404333 #####do#1set(#1repl?-header-slot-val'e#re@'est#&3#v33 ##SS#iF'nes5#despite#claiming#to#spea&#:FFT/0.05#doesnCt#'nderstand ##SS#ch'n&ed#Frans(er-encoding.#Jrrr.#,o#we#j'st#t'rn#it#o((. ##1t'rn-o((-ch'n&ed-trans(er-encoding#re@'est33 1de('n#t'rn-o((-ch'n&ed-trans(er-encoding#1re@'est3 ##1set(#1re@'est-repl?-strateg?#re@'est3 ########1remove#:ch'n&ed#1re@'est-repl?-strateg?#re@'est3333
Within the with-http-bod? o' sho'tcast, you #ctu#lly !tre#* the 3P3 d#t#. &he 'unction pla?-songs t#9e! the !tre#* to 6hich it !hould 6rite the d#t#, the !ong !ource, #nd the *et#d#t# inter?#l it !hould u!e or NIL i' the client doe!n@t 6#nt *et#d#t#. &he !tre#* i! the !oc9et obt#ined 'ro* the reFue!t ob<ect, the !ong !ource i! obt#ined by c#lling (ind-song-so'rce, #nd the *et#d#t# inter?#l co*e! 'ro* the glob#l ?#ri#ble Umetadata-intervalU. &he type o' !ong !ource i! controlled by the ?#ri#ble Usong-so'rce-t?peU, 6hich 'or no6 you c#n !et to singleton in order to u!e the simple-song-@'e'e you i*ple*ented pre?iou!ly.
1de(parameter#Umetadata-intervalU#1e)pt#!#0!33 1de(parameter#Usong-so'rce-t?peU#Csingleton3
&he 'unction pla?-songs it!el' doe!n@t do *uch--it loop! c#lling the 'unction pla?-c'rrent, 6hich doe! #ll the he#?y li'ting o' !ending the content! o' # !ingle 3P3 'ile, !9ipping the I+3 t#g #nd e*bedding IC4 *et#d#t#. &he only 6rin9le i! th#t you need to 9eep tr#c9 o' 6hen to !end the *et#d#t#. Since you *u!t !end *et#d#t# chun9! #t # 'i.ed inter?#l!, reg#rdle!! o' 6hen you h#ppen to !6itch 'ro* one 3P3 'ile to the ne.t, e#ch ti*e you c#ll pla?-c'rrent you need to tell it 6hen the ne.t
*et#d#t# i! due, #nd 6hen it return!, it *u!t tell you the !#*e thing !o you c#n p#!! the in'or*#tion to the ne.t c#ll to pla?-c'rrent. I' pla?-c'rrent get! NIL 'ro* the !ong !ource, it return! NIL, 6hich #llo6! the pla?-songs LOOP to end. In #ddition to h#ndling the looping, pla?-songs #l!o pro?ide! # HANDLER-CASE to tr#p the error th#t 6ill be !ign#led 6hen the 3P3 client di!connect! 'ro* the !er?er #nd one o' the 6rite! to the !oc9et, do6n in pla?-c'rrent, '#il!. Since the HANDLER-CASE i! out!ide the LOOP, h#ndling the error 6ill bre#9 out o' the loop, #llo6ing pla?-songs to return.
1de('n#pla?-songs#1stream#song-so'rce#metadata-interval3 ##1handler-case# ######1loop #########(or#ne)t-metadata#=#metadata-interval #########then#1pla?-c'rrent# ###############stream# ###############song-so'rce ###############ne)t-metadata ###############metadata-interval3 #########while#ne)t-metadata3 ####1error#1e3#1(ormat#Utrace-o'tp'tU#4$a'ght#error#in#pla?-songs:#7a4#e3333
/in#lly, you@re re#dy to i*ple*ent pla?-c'rrent, 6hich #ctu#lly !end! the Shoutc#!t d#t#. &he b#!ic ide# i! th#t you get the current !ong 'ro* the !ong !ource, open the !ong@! 'ile, #nd then loop re#ding d#t# 'ro* the 'ile #nd 6riting it to the !oc9et until either you re#ch the end o' the 'ile or the current !ong i! no longer the current !ong. &here #re only t6o co*plic#tion!: 5ne i! th#t you need to *#9e !ure you !end the *et#d#t# #t the correct inter?#l. &he other i! th#t i' the 'ile !t#rt! 6ith #n I+3 t#g, you 6#nt to !9ip it. I' you don@t 6orry too *uch #bout I;5 e''iciency, you c#n i*ple*ent pla?-c'rrent li9e thi!:
1de('n#pla?-c'rrent#1o't#song-so'rce#ne)t-metadata#metadata-interval3 ##1let#11song#1c'rrent-song#song-so'rce333 ####1when#song ######1let#11metadata#1ma&e-ic?-metadata#1title#song3333 ########1with-open-(ile#1mp3#1(ile#song33 ##########1'nless#1(ile-position#mp3#1id3-si*e#song33 ############1error#4$anCt#s&ip#to#position#7d#in#7a4#1id3-si*e#song3#1(ile#song333 ##########1loop#(or#b?te#=#1read-b?te#mp3#nil#nil3 #############while#1and#b?te#1still-c'rrent-p#song#song-so'rce33#do ###############1write-b?te#b?te#o't3 ###############1dec(#ne)t-metadata3 #############when#1and#1*erop#ne)t-metadata3#metadata-interval3#do ###############1write-se@'ence#metadata#o't3 ###############1set(#ne)t-metadata#metadata-interval33 ##########1ma?be-move-to-ne)t-song#song#song-so'rce333 ######ne)t-metadata333
&hi! 'unction get! the current !ong 'ro* the !ong !ource #nd get! # bu''er cont#ining the *et#d#t# it@ll need to !end by p#!!ing the title to ma&e-ic?-metadata. &hen it open! the 'ile #nd !9ip! p#!t the I+3 t#g u!ing the t6o-#rgu*ent 'or* o' FILE-POSITION. &hen it co**ence! re#ding byte! 'ro* the 'ile #nd 6riting the* to the reFue!t !tre#*.2 It@ll bre#9 out o' the loop either 6hen it re#che! the end o' the 'ile or 6hen the !ong !ource@! current !ong ch#nge! out 'ro* under it. In the *e#nti*e, 6hene?er ne)t-metadata get! to Aero Bi' you@re !uppo!ed to !end *et#d#t# #t #llC, it 6rite! metadata to the !tre#* #nd re!et! ne)t-metadata.
5nce it 'ini!he! the loop, it chec9! to !ee i' the !ong i! !till the !ong !ource@! current !ongG i' it i!, th#t *e#n! it bro9e out o' the loop bec#u!e it re#d the 6hole 'ile, in 6hich c#!e it tell! the !ong !ource to *o?e to the ne.t !ong. 5ther6i!e, it bro9e out o' the loop bec#u!e !o*eone ch#nged the current !ong out 'ro* under it, #nd it <u!t return!. In either c#!e, it return! the nu*ber o' byte! le't be'ore the ne.t *et#d#t# i! due !o it c#n be p#!!ed in the ne.t c#ll to pla?-c'rrent., &he 'unction ma&e-ic?-metadata, 6hich t#9e! the title o' the current !ong #nd gener#te! #n #rr#y o' byte! cont#ining # properly 'or*#tted chun9 o' IC4 *et#d#t#, i! #l!o !tr#ight'or6#rd.)
1de('n#ma&e-ic?-metadata#1title3 ##1letU#11te)t#1(ormat#nil#4,treamFitle=C7aCS4#1s'bstit'te#NY,pace#NYC#title333 #########1bloc&s#1ceiling#1length#te)t3#0633 #########1b'((er#1ma&e-arra?#102#1U#bloc&s#0633 #############################:element-t?pe#C1'nsigned-b?te#R3 #############################:initial-element# 333 ####1set(#1are(#b'((er# 3#bloc&s3 ####1loop# #######(or#char#across#te)t #######(or#i#(rom#0# #######do#1set(#1are(#b'((er#i3#1char-code#char333 ####b'((er33
+epending on ho6 your p#rticul#r i!p i*ple*ent#tion h#ndle! it! !tre#*!, #nd #l!o ho6 *#ny 3P3 client! you 6#nt to !er?e #t once, the !i*ple ?er!ion o' pla?-c'rrent *#y or *#y not be e''icient enough. &he potenti#l proble* 6ith the !i*ple i*ple*ent#tion i! th#t you h#?e to c#ll READ-BYTE #nd WRITE-BYTE 'or e?ery byte you tr#n!'er. It@! po!!ible th#t e#ch c#ll *#y re!ult in # rel#ti?ely e.pen!i?e !y!te* c#ll to re#d or 6rite one byte. %nd e?en i' i!p i*ple*ent! it! o6n !tre#*! 6ith intern#l bu''ering !o not e?ery c#ll to READ-BYTE or WRITE-BYTE re!ult! in # !y!te* c#ll, 'unction c#ll! !till #ren@t 'ree. In p#rticul#r, in i*ple*ent#tion! th#t pro?ide u!er-e.ten!ible !tre#*! u!ing !oc#lled =r#y Stre#*!, READ-BYTE #nd WRITE-BYTE *#y re!ult in # generic 'unction c#ll under the co?er! to di!p#tch on the cl#!! o' the !tre#* #rgu*ent. While generic 'unction di!p#tch i! nor*#lly !peedy enough th#t you don@t h#?e to 6orry #bout it, it@! # bit *ore e.pen!i?e th#n # nongeneric 'unction c#ll #nd thu! not !o*ething you nece!!#rily 6#nt to do !e?er#l *illion ti*e! in # 'e6 *inute! i' you c#n #?oid it. % *ore e''icient, i' !lightly *ore co*ple., 6#y to i*ple*ent pla?-c'rrent i! to re#d #nd 6rite *ultiple byte! #t # ti*e u!ing the 'unction! READ-SEQUENCE #nd WRITE-SEQUENCE. &hi! #l!o gi?e! you # ch#nce to *#tch your 'ile re#d! 6ith the n#tur#l bloc9 !iAe o' the 'ile !y!te*, 6hich 6ill li9ely gi?e you the be!t di!9 throughput. 5' cour!e, no *#tter 6h#t bu''er !iAe you u!e, 9eeping tr#c9 o' 6hen to !end the *et#d#t# beco*e! # bit *ore co*plic#ted. % *ore e''icient ?er!ion o' pla?c'rrent th#t u!e! READ-SEQUENCE #nd WRITE-SEQUENCE *ight loo9 li9e thi!:
1de('n#pla?-c'rrent#1o't#song-so'rce#ne)t-metadata#metadata-interval3 ##1let#11song#1c'rrent-song#song-so'rce333 ####1when#song ######1let#11metadata#1ma&e-ic?-metadata#1title#song333 ############1b'((er#1ma&e-arra?#si*e#:element-t?pe#C1'nsigned-b?te#R3333 ########1with-open-(ile#1mp3#1(ile#song33 ##########1labels#11write-b'((er#1start#end3 #####################1i(#metadata-interval #######################1write-b'((er-with-metadata#start#end3 #######################1write-se@'ence#b'((er#o't#:start#start#:end#end333
###################1write-b'((er-with-metadata#1start#end3 #####################1cond #######################11/#ne)t-metadata#1-#end#start33 ########################1write-se@'ence#b'((er#o't#:start#start#:end#end3 ########################1dec(#ne)t-metadata#1-#end#start333 #######################1t# ########################1let#11middle#12#start#ne)t-metadata333 ##########################1write-se@'ence#b'((er#o't#:start#start#:end#middle3 ##########################1write-se@'ence#metadata#o't3 ##########################1set(#ne)t-metadata#metadata-interval3 ##########################1write-b'((er-with-metadata#middle#end333333 ############1m'ltiple-val'e-bind#1s&ip-bloc&s#s&ip-b?tes3 ################1(loor#1id3-si*e#song3#1length#b'((er33 ##############1'nless#1(ile-position#mp3#1U#s&ip-bloc&s#1length#b'((er333 ################1error#4$o'ldnCt#s&ip#over#7d#7d#b?te#bloc&s.4 #######################s&ip-bloc&s#1length#b'((er333 ##############1loop#(or#end#=#1read-se@'ence#b'((er#mp33# #################(or#start#=#s&ip-b?tes#then# #################do#1write-b'((er#start#end3 #################while#1and#1=#end#1length#b'((er33 ############################1still-c'rrent-p#song#song-so'rce333 ##############1ma?be-move-to-ne)t-song#song#song-so'rce33333 ######ne)t-metadata333
:o6 you@re re#dy to put #ll the piece! together. In the ne.t ch#pter you@ll 6rite # Web inter'#ce to the Shoutc#!t !er?er de?eloped in thi! ch#pter, u!ing the 3P3 d#t#b#!e 'ro* Ch#pter 22 #! the !ource o' !ong!.
1&he
?er!ion o' N33S !hipped 6ith $ed >#t ,.0 #nd ).0 #nd /edor# no longer 9no6! ho6 to pl#y 3P3! bec#u!e the 'ol9! #t $ed >#t 6ere 6orried #bout the licen!ing i!!ue! rel#ted to the 3P3 codec. &o get #n N33S 6ith 3P3 !upport on the!e ?er!ion! o' inu., you c#n gr#b the !ource 'ro* http://www.)mms.org #nd build it your!el'. 5r, !ee http://www.(edora([email protected]/N)mms-mp3 'or in'or*#tion #bout other po!!ibilitie!.
2&o
'urther con'u!e *#tter!, there@! # di''erent !tre#*ing protocol c#lled ;cecast. &here !ee*! to be no connection bet6een the IC4 he#der u!ed by Shoutc#!t #nd the Icec#!t protocol.
3&echnic#lly,
the i*ple*ent#tion in thi! ch#pter 6ill #l!o be *#nipul#ted 'ro* t6o thre#d!--the %llegroSer?e thre#d running the Shoutc#!t !er?er #nd the $(P thre#d. 7ut you c#n li?e 6ith the r#ce condition 'or no6. I@ll di!cu!! ho6 to u!e loc9ing to *#9e code thre#d !#'e in the ne.t ch#pter.
-%nother
thing you *#y 6#nt to do 6hile 6or9ing on thi! code i! to e?#lu#te the 'or* 1net.aserve::deb'g-on#:notrap3. &hi! tell! %llegroSer?e to not tr#p error! !ign#led by your code, 6hich 6ill #llo6 you to debug the* in the nor*#l i!p debugger. In S I3( thi! 6ill pop up # S I3( debugger bu''er <u!t li9e #ny other error.
5Shoutc#!t
he#der! #re u!u#lly !ent in lo6erc#!e, !o you need to e!c#pe the n#*e! o' the 9ey6ord !y*bol! u!ed to identi'y the* to %llegroSer?e to 9eep the i!p re#der 'ro* con?erting the* to #ll upperc#!e. &hu!, you@d 6rite :Xic?-metaintX r#ther th#n :ic?-metaint. 4ou could #l!o 6rite :YiYcY?-YmYeYtYaYiYnYt, but th#t@d be !illy.
0&he
'unction t'rn-o((-ch'n&ed-trans(er-encoding i! # bit o' # 9ludge. &here@! no 6#y to turn o'' chun9ed tr#n!'er encoding ?i# %llegroSer?e@! o''ici#l %PI! 6ithout !peci'ying # content length bec#u!e #ny client th#t #d?erti!e! it!el' #! #n >&&P;1.1 client, 6hich i&une! doe!, i! !uppo!ed to under!t#nd it. 7ut thi! doe! the tric9.
23o!t
3P3-pl#ying !o't6#re 6ill di!pl#y the *et#d#t# !o*e6here in the u!er inter'#ce. >o6e?er, the N33S progr#* on inu. by de'#ult doe!n@t. &o get N33S to di!pl#y Shoutc#!t *et#d#t#, pre!! CtrlEP to !ee the Pre'erence! p#ne. &hen in the %udio I;5 Plugin! t#b Bthe le't*o!t t#b in ?er!ion 1.2.10C, !elect the 3P(= #yer 1;2;3 Pl#yer Blibmpg0!3.soC #nd hit the Con'igure button. &hen !elect the Stre#*ing t#b on the con'igur#tion 6indo6, #nd #t the botto* o' the t#b in the S>58&C%S&;Icec#!t !ection, chec9 the H(n#ble S>58&C%S&;Icec#!t title !tre#*ingH bo..
,/ol9!
co*ing to Co**on i!p 'ro* Sche*e *ight 6onder 6hy pla?-c'rrent c#n@t <u!t c#ll it!el' recur!i?ely. In Sche*e th#t 6ould 6or9 'ine !ince Sche*e i*ple*ent#tion! #re reFuired by the Sche*e !peci'ic#tion to !upport H#n unbounded nu*ber o' #cti?e t#il c#ll!.H Co**on i!p i*ple*ent#tion! #re #llo6ed to h#?e thi! property, but it i!n@t reFuired by the l#ngu#ge !t#nd#rd. &hu!, in Co**on i!p the idio*#tic 6#y to 6rite loop! i! 6ith # looping con!truct, not 6ith recur!ion.
)&hi!
'unction #!!u*e!, #! h#! other code you@?e 6ritten, th#t your i!p i*ple*ent#tion@! intern#l ch#r#cter encoding i! %SCII or # !uper!et o' %SCII, !o you c#n u!e CHAR-CODE to tr#n!l#te i!p CHARACTER ob<ect! to byte! o' %SCII d#t#.
"%ay%ists
&he b#!ic ide# behind the inter'#ce 6ill be th#t e#ch 3P3 client th#t connect! to the Shoutc#!t !er?er get! it! o6n pla0list, 6hich !er?e! #! the !ource o' !ong! 'or the Shoutc#!t !er?er. % pl#yli!t 6ill #l!o pro?ide '#cilitie! beyond tho!e needed by the Shoutc#!t !er?er: through the Web inter'#ce the u!er 6ill be #ble to #dd !ong! to the pl#yli!t, delete !ong! #lre#dy in the pl#yli!t, #nd reorder the pl#yli!t by !orting #nd !hu''ling. 4ou c#n de'ine # cl#!! to repre!ent pl#yli!t! li9e thi!:
1de(class#pla?list#13 ##11id###########:accessor#id###########:initarg#:id3 ###1songs-table##:accessor#songs-table##:init(orm#1ma&e-pla?list-table33 ###1c'rrent-song#:accessor#c'rrent-song#:init(orm#Uempt?-pla?list-songU3 ###1c'rrent-id)##:accessor#c'rrent-id)##:init(orm# 3 ###1ordering#####:accessor#ordering#####:init(orm#:alb'm3 ###1sh'((le######:accessor#sh'((le######:init(orm#:none3 ###1repeat#######:accessor#repeat#######:init(orm#:none3 ###1'ser-agent###:accessor#'ser-agent###:init(orm#4+n&nown43 ###1loc&#########:reader###loc&#########:init(orm#1ma&e-process-loc&3333
&he id o' # pl#yli!t i! the 9ey you e.tr#ct 'ro* the reFue!t ob<ect p#!!ed to (ind-song-so'rce 6hen loo9ing up # pl#yli!t. 4ou don@t #ctu#lly need to !tore it in the pla?list ob<ect, but it *#9e! debugging # bit e#!ier i' you c#n 'ind out 'ro* #n #rbitr#ry pl#yli!t ob<ect 6h#t it! id i!. &he he#rt o' the pl#yli!t i! the songs-table !lot, 6hich 6ill hold # table ob<ect. &he !che*# 'or thi! t#ble 6ill be the !#*e #! 'or the *#in 3P3 d#t#b#!e. &he 'unction ma&e-pla?list-table, 6hich you u!e to initi#liAe songs-table, i! !i*ply thi!:
1de('n#ma&e-pla?list-table#13 ##1ma&e-instance#Ctable#:schema#Ump3-schemaU33
&he P#c9#ge 4ou c#n de'ine the p#c9#ge 'or the code in thi! ch#pter 6ith the 'ollo6ing DEFPAC+AGE:
1de(pac&age#:com.gigamon&e?s.mp3-browser ##1:'se#:common-lisp ########:net.aserve ########:com.gigamon&e?s.html ########:com.gigamon&e?s.sho'tcast ########:com.gigamon&e?s.'rl-('nction ########:com.gigamon&e?s.mp3-database ########:com.gigamon&e?s.id3v!3 ##1:import-(rom#:acl-soc&et ################:ipaddr-to-dotted ################:remote-host3 ##1:import-(rom#:m'ltiprocessing ################:ma&e-process-loc& ################:with-process-loc&3 ##1:e)port#:start-mp3-browser33
7ec#u!e thi! i! # high-le?el #pplic#tion, it u!e! # lot o' lo6er-le?el p#c9#ge!. It #l!o i*port! three !y*bol! 'ro* the I$L-,;$M-F p#c9#ge #nd t6o *ore 'ro* %+LF9T.;$-,,98J !ince it <u!t need! tho!e 'i?e #nd not the other 13) !y*bol! tho!e t6o p#c9#ge! e.port. 7y !toring the li!t o' !ong! #! # t#ble, you c#n u!e the d#t#b#!e 'unction! 'ro* Ch#pter 22 to *#nipul#te the pl#yli!t: you c#n #dd to the pl#yli!t 6ith insert-row, delete !ong! 6ith deleterows, #nd reorder the pl#yli!t 6ith sort-rows #nd sh'((le-table. &he c'rrent-song #nd c'rrent-id) !lot! 9eep tr#c9 o' 6hich !ong i! pl#ying: c'rrentsong i! #n #ctu#l song ob<ect, 6hile c'rrent-id) i! the inde. into the songs-table o' the ro6 repre!enting the current !ong. 4ou@ll !ee in the !ection H3#nipul#ting the Pl#yli!tH ho6 to *#9e !ure c'rrent-song i! upd#ted 6hene?er c'rrent-id) ch#nge!. &he ordering #nd sh'((le !lot! hold in'or*#tion #bout ho6 the !ong! in songs-table #re to be ordered. &he ordering !lot hold! # 9ey6ord th#t tell! ho6 the songs-table !hould be !orted 6hen it@! not !hu''led. &he leg#l ?#lue! #re :genre, :artist, :alb'm, #nd :song. &he sh'((le# !lot hold! one o' the 9ey6ord! :none, :song, or :alb'm, 6hich !peci'ie! ho6 songs-table !hould be !hu''led, i' #t #ll. &he repeat !lot #l!o hold! # 9ey6ord, one o' :none, :song, or :all, 6hich !peci'ie! the repe#t *ode 'or the pl#yli!t. I' repeat i! :none, #'ter the l#!t !ong in the songs-table h#! been pl#yed, the c'rrent-song goe! b#c9 to # de'#ult 3P3. When :repeat i! :song, the pl#yli!t 9eep! returning the !#*e c'rrent-song 'ore?er. %nd i' it@! :all, #'ter the l#!t !ong, c'rrent-song goe! b#c9 to the 'ir!t !ong. &he 'ser-agent !lot hold! the ?#lue o' the 8!er-%gent he#der !ent by the 3P3 client in it! reFue!t 'or the !tre#*. 4ou need to hold onto thi! ?#lue purely 'or u!e in the Web inter'#ce--the 8!er-%gent he#der identi'ie! the progr#* th#t *#de the reFue!t, !o you c#n di!pl#y the ?#lue on the p#ge th#t li!t! #ll the pl#yli!t! to *#9e it e#!ier to tell 6hich pl#yli!t goe! 6ith 6hich connection 6hen *ultiple client! connect. /in#lly, the loc& !lot hold! # process loc$ cre#ted 6ith the 'unction ma&e-process-loc&, 6hich i! p#rt o' %llegro@! %+LF9T.;$-,,98J p#c9#ge. 4ou@ll need to u!e th#t loc9 in cert#in 'unction! th#t *#nipul#te pla?list ob<ect! to en!ure th#t only one thre#d #t # ti*e *#nipul#te! # gi?en pl#yli!t ob<ect. 4ou c#n de'ine the 'ollo6ing *#cro, built upon the with-process-loc& *#cro 'ro*
%+LF9T.;$-,,98J, to gi?e #n e#!y 6#y to 6r#p # body o' code th#t !hould be per'or*ed 6hile holding # pl#yli!t@! loc9:
1de(macro#with-pla?list-loc&ed#11pla?list3#>bod?#bod?3 ##B1with-process-loclocpla?list33 #####5Pbod?33
&he with-process-loc& *#cro #cFuire! e.clu!i?e #cce!! to the proce!! loc9 gi?en #nd then e.ecute! the body 'or*!, rele#!ing the loc9 #'ter6#rd. 7y de'#ult, with-process-loc& #llo6! recur!i?e loc9!, *e#ning the !#*e thre#d c#n !#'ely #cFuire the !#*e loc9 *ultiple ti*e!.
4ou@ll #l!o need to de'ine # proce!! loc9 to protect #cce!! to thi! h#!h t#ble li9e thi!:
1de(parameter#Upla?lists-loc&U#1ma&e-process-loc&#:name#4pla?lists-loc&433
&hen de'ine # 'unction th#t loo9! up # pl#yli!t gi?en #n I+, cre#ting # ne6 pla?list ob<ect i' nece!!#ry #nd u!ing with-process-loc& to en!ure th#t only one thre#d #t # ti*e *#nipul#te! the h#!h t#ble.1
1de('n#loo&'p-pla?list#1id3 ##1with-process-locUpla?lists-loc&U3 ####1or#1gethash#id#Upla?listsU3 ########1set(#1gethash#id#Upla?listsU3#1ma&e-instance#Cpla?list#:id#id33333
&hen you c#n i*ple*ent (ind-song-so'rce on top o' th#t 'unction #nd #nother, pla?list-id, th#t t#9e! #n %llegroSer?e reFue!t ob<ect #nd return! the #ppropri#te pl#yli!t identi'ier. &he (indsong-so'rce 'unction i! #l!o 6here you gr#b the 8!er-%gent !tring out o' the reFue!t ob<ect #nd !t#!h it in the pl#yli!t ob<ect.
1de(method#(ind-song-so'rce#11t?pe#1e@l#Cpla?list33#re@'est3 ##1let#11pla?list#1loo&'p-pla?list#1pla?list-id#re@'est3333 ####1with-pla?list-loc&ed#1pla?list3 ######1let#11'ser-agent#1header-slot-val'e#re@'est#:'ser-agent333 ########1when#'ser-agent#1set(#1'ser-agent#pla?list3#'ser-agent3333 ####pla?list33
&he tric9, then, i! ho6 you i*ple*ent pla?list-id, the 'unction th#t e.tr#ct! the identi'ier 'ro* the reFue!t ob<ect. 4ou h#?e # couple option!, e#ch 6ith di''erent i*plic#tion! 'or the u!er inter'#ce. 4ou c#n pull 6h#te?er in'or*#tion you 6#nt out o' the reFue!t ob<ect, but ho6e?er you decide to identi'y the client, you need !o*e 6#y 'or the u!er o' the Web inter'#ce to get hoo9ed up to the right pl#yli!t. /or no6 you c#n t#9e #n #ppro#ch th#t H<u!t 6or9!H #! long #! there@! only one 3P3 client per *#chine connecting to the !er?er #nd #! long #! the u!er i! bro6!ing the Web inter'#ce 'ro* the *#chine
running the 3P3 client: you@ll u!e the IP #ddre!! o' the client *#chine #! the identi'ier. &hi! 6#y you c#n 'ind the right pl#yli!t 'or # reFue!t reg#rdle!! o' 6hether the reFue!t i! 'ro* the 3P3 client or # Web bro6!er. 4ou 6ill, ho6e?er, pro?ide # 6#y in the Web inter'#ce to !elect # di''erent pl#yli!t 'ro* the bro6!er, !o the only re#l con!tr#int thi! choice put! on the #pplic#tion i! th#t there c#n be only one connected 3P3 client per client IP #ddre!!.2 &he i*ple*ent#tion o' pla?list-id loo9! li9e thi!:
1de('n#pla?list-id#1re@'est3 ##1ipaddr-to-dotted#1remote-host#1re@'est-soc&et#re@'est3333
&he 'unction re@'est-soc&et i! p#rt o' %llegroSer?e, 6hile remote-host #nd ipaddr-todotted #re p#rt o' %llegro@! !oc9et libr#ry. &o *#9e # pl#yli!t u!#ble #! # !ong !ource by the Shoutc#!t !er?er, you need to de'ine *ethod! on c'rrent-song, still-c'rrent-p, #nd ma?be-move-to-ne)t-song th#t !peci#liAe their so'rce p#r#*eter on pla?list. &he c'rrent-song *ethod i! #lre#dy t#9en c#re o': by de'ining the #cce!!or c'rrent-song on the epony*ou! !lot, you #uto*#tic#lly got # c'rrentsong *ethod !peci#liAed on pla?list th#t return! the ?#lue o' th#t !lot. >o6e?er, to *#9e #cce!!e! to the pla?list thre#d !#'e, you need to loc9 the pla?list be'ore #cce!!ing the c'rrent-song# !lot. In thi! c#!e, the e#!ie!t 6#y i! to de'ine #n :aro'nd *ethod li9e the 'ollo6ing:
1de(method#c'rrent-song#:aro'nd#11pla?list#pla?list33 ##1with-pla?list-loc&ed#1pla?list3#1call-ne)t-method333
I*ple*enting still-c'rrent-p i! #l!o Fuite !i*ple, #!!u*ing you c#n be !ure th#t c'rrentsong get! upd#ted 6ith # ne6 song ob<ect only 6hen the current !ong #ctu#lly ch#nge!. %g#in, you need to #cFuire the proce!! loc9 to en!ure you get # con!i!tent ?ie6 o' the pla?list@! !t#te.
1de(method#still-c'rrent-p#1song#1pla?list#pla?list33 ##1with-pla?list-loc&ed#1pla?list3 ####1e@l#song#1c'rrent-song#pla?list3333
&he tric9, then, i! to *#9e !ure the c'rrent-song !lot get! upd#ted #t the right ti*e!. >o6e?er, the current !ong c#n ch#nge in # nu*ber o' 6#y!. &he ob?iou! one i! 6hen the Shoutc#!t !er?er c#ll! ma?be-move-to-ne)t-song. 7ut it c#n #l!o ch#nge 6hen !ong! #re #dded to the pl#yli!t, 6hen the Shoutc#!t !er?er h#! run out o' !ong!, or e?en i' the pl#yli!t@! repe#t *ode i! ch#nged. $#ther th#n trying to 6rite code !peci'ic to e?ery !itu#tion to deter*ine 6hether to upd#te c'rrentsong, you c#n de'ine # 'unction, 'pdate-c'rrent-i(-necessar?, th#t upd#te! c'rrentsong i' the song ob<ect in c'rrent-song no longer *#tche! the 'ile th#t the c'rrent-id) !lot !#y! !hould be pl#ying. &hen, i' you c#ll thi! 'unction #'ter #ny *#nipul#tion o' the pl#yli!t th#t could po!!ibly put tho!e t6o !lot! out o' !ync, you@re !ure to 9eep c'rrent-song !et properly. >ere #re 'pdate-c'rrent-i(-necessar? #nd it! helper 'unction!:
1de('n#'pdate-c'rrent-i(-necessar?#1pla?list3 ##1'nless#1e@'al#1(ile#1c'rrent-song#pla?list33 #################1(ile-(or-c'rrent-id)#pla?list33 ####1reset-c'rrent-song#pla?list333 1de('n#(ile-(or-c'rrent-id)#1pla?list3 ##1i(#1at-end-p#pla?list3 ####nil ####1col'mn-val'e#1nth-row#1c'rrent-id)#pla?list3#1songs-table#pla?list33#:(ile333 1de('n#at-end-p#1pla?list3 ##1/=#1c'rrent-id)#pla?list3#1table-si*e#1songs-table#pla?list3333
4ou don@t need to #dd loc9ing to the!e 'unction! !ince they@ll be c#lled only 'ro* 'unction! th#t 6ill t#9e c#re o' loc9ing the pl#yli!t 'ir!t. &he 'unction reset-c'rrent-song introduce! one *ore 6rin9le: bec#u!e you 6#nt the pl#yli!t to pro?ide #n endle!! !tre#* o' 3P3! to the client, you don@t 6#nt to e?er !et c'rrent-song to NIL. In!te#d, 6hen # pl#yli!t run! out o' !ong! to pl#y--6hen songs-table i! e*pty or #'ter the l#!t !ong h#! been pl#yed #nd repeat i! !et to :none--then you need to !et c'rrent-song to # !peci#l !ong 6ho!e 'ile i! #n 3P3 o' !ilence3 #nd 6ho!e title e.pl#in! 6hy no *u!ic i! pl#ying. >ere@! !o*e code to de'ine t6o p#r#*eter!, Uempt?-pla?list-songU #nd Uend-o(-pla?list-songU, e#ch !et to # !ong 6ith the 'ile n#*ed by Usilence-mp3U #! their 'ile #nd #n #ppropri#te title:
1de(parameter#Usilence-mp3U#...3 1de('n#ma&e-silent-song#1title#>optional#1(ile#Usilence-mp3U33 ##1ma&e-instance ###Csong# ###:(ile#(ile ###:title#title ###:id3-si*e#1i(#1id3-p#(ile3#1si*e#1read-id3#(ile33# 333 1de(parameter#Uempt?-pla?list-songU#1ma&e-silent-song#4Tla?list#empt?.433 1de(parameter#Uend-o(-pla?list-songU#1ma&e-silent-song#4It#end#o(#pla?list.433
reset-c'rrent-song u!e! the!e p#r#*eter! 6hen the c'rrent-id) doe!n@t point to # ro6 in songs-table. 5ther6i!e, it !et! c'rrent-song to # song ob<ect repre!enting the current ro6.
1de('n#reset-c'rrent-song#1pla?list3 ##1set( ###1c'rrent-song#pla?list3# ###1cond #####11empt?-p#pla?list3#Uempt?-pla?list-songU3 #####11at-end-p#pla?list3#Uend-o(-pla?list-songU3 #####1t#1row-/song#1nth-row#1c'rrent-id)#pla?list3#1songs-table#pla?list3333333 1de('n#row-/song#1song-db-entr?3 ##1with-col'mn-val'es#1(ile#song#artist#alb'm#id3-si*e3#song-db-entr? ####1ma&e-instance #####Csong #####:(ile#(ile #####:title#1(ormat#nil#47a#b?#7a#(rom#7a4#song#artist#alb'm3 #####:id3-si*e#id3-si*e333 1de('n#empt?-p#1pla?list3 ##1*erop#1table-si*e#1songs-table#pla?list3333
:o6, #t l#!t, you c#n i*ple*ent the *ethod on ma?be-move-to-ne)t-song th#t *o?e! c'rrent-id) to it! ne.t ?#lue, b#!ed on the pl#yli!t@! repe#t *ode, #nd then c#ll! 'pdatec'rrent-i(-necessar?. 4ou don@t ch#nge c'rrent-id) 6hen it@! #lre#dy #t the end o' the pl#yli!t bec#u!e you 6#nt it to 9eep it! current ?#lue, !o it@ll point #t the ne.t !ong you #dd to the pl#yli!t. &hi! 'unction *u!t loc9 the pl#yli!t be'ore *#nipul#ting it !ince it@! c#lled by the Shoutc#!t !er?er code, 6hich doe!n@t do #ny loc9ing.
1de(method#ma?be-move-to-ne)t-song#1song#1pla?list#pla?list33 ##1with-pla?list-loc&ed#1pla?list3 ####1when#1still-c'rrent-p#song#pla?list3
+eleting !ong! i! # bit !i*plerG you <u!t need to be #ble to delete !ong! 'ro* the songs-table th#t *#tch p#rticul#r criteri#--either # p#rticul#r !ong or #ll !ong! in # p#rticul#r genre, by # p#rticul#r #rti!t, or 'ro* # p#rticul#r #lbu*. So, you c#n pro?ide # delete-songs 'unction th#t t#9e! 9ey6ord;?#lue p#ir!, 6hich #re u!ed to con!truct # matching :where cl#u!e you c#n p#!! to the delete-rows d#t#b#!e 'unction. %nother co*plic#tion th#t #ri!e! 6hen deleting !ong! i! th#t c'rrent-id) *#y need to ch#nge. %!!u*ing the current !ong i!n@t one o' the one! <u!t deleted, you@d li9e it to re*#in the current !ong. 7ut i' !ong! be'ore it in songs-table #re deleted, it@ll be in # di''erent po!ition in the t#ble #'ter the delete. So #'ter # c#ll to delete-rows, you need to loo9 'or the ro6 cont#ining the current !ong #nd
re!et c'rrent-id). I' the current !ong h#! it!el' been deleted, then, 'or l#c9 o' #nything better to do, you c#n re!et c'rrent-id) to Aero. %'ter upd#ting c'rrent-id), c#lling 'pdate-c'rrenti(-necessar? 6ill t#9e c#re o' upd#ting c'rrent-song. %nd i' c'rrent-id) ch#nged but !till point! #t the !#*e !ong, c'rrent-song 6ill be le't #lone.
1de('n#delete-songs#1pla?list#>rest#names-and-val'es3 ##1delete-rows ###:(rom#1songs-table#pla?list3 ###:where#1appl?#NCmatching#1songs-table#pla?list3#names-and-val'es33 ##1set(#1c'rrent-id)#pla?list3#1or#1position-o(-c'rrent#pla?list3# 33 ##1'pdate-c'rrent-i(-necessar?#pla?list33 1de('n#position-o(-c'rrent#1pla?list3 ##1letU#11table#1songs-table#pla?list33 #########1matcher#1matching#table#:(ile#1(ile#1c'rrent-song#pla?list3333 #########1pos# 33 ####1do-rows#1row#table3 ######1when#1('ncall#matcher#row3 ########1ret'rn-(rom#position-o(-c'rrent#pos33 ######1inc(#pos3333
4ou c#n #l!o pro?ide # 'unction to co*pletely cle#r the pl#yli!t, 6hich u!e! delete-all-rows #nd doe!n@t h#?e to 6orry #bout 'inding the current !ong !ince it h#! ob?iou!ly been deleted. &he c#ll to 'pdate-c'rrent-i(-necessar? 6ill t#9e c#re o' !etting c'rrent-song to NIL.
1de('n#clear-pla?list#1pla?list3 ##1delete-all-rows#1songs-table#pla?list33 ##1set(#1c'rrent-id)#pla?list3# 3 ##1'pdate-c'rrent-i(-necessar?#pla?list33
Sorting #nd !hu''ling the pl#yli!t #re rel#ted in th#t the pl#yli!t i! #l6#y! either !orted or !hu''led. &he sh'((le !lot !#y! 6hether the pl#yli!t !hould be !hu''led #nd i' !o ho6. I' it@! !et to :none, then the pl#yli!t i! ordered #ccording to the ?#lue in the ordering !lot. When sh'((le i! :song, the pl#yli!t 6ill be r#ndo*ly per*uted. %nd 6hen it@! !et to :alb'm, the li!t o' #lbu*! i! r#ndo*ly per*uted, but the !ong! 6ithin e#ch #lbu* #re li!ted in tr#c9 order. &hu!, the sort-pla?list 'unction, 6hich 6ill be c#lled by the Web inter'#ce code 6hene?er the u!er !elect! # ne6 ordering, need! to !et ordering to the de!ired ordering #nd !et sh'((le to :none be'ore c#lling orderpla?list, 6hich #ctu#lly doe! the !ort. %! in delete-songs, you need to u!e position-o(c'rrent to re!et c'rrent-id) to the ne6 loc#tion o' the current !ong. >o6e?er, thi! ti*e you don@t need to c#ll 'pdate-c'rrent-i(-necessar? !ince you 9no6 the current !ong i! !till in the t#ble.
1de('n#sort-pla?list#1pla?list#ordering3 ##1set(#1ordering#pla?list3#ordering3 ##1set(#1sh'((le#pla?list3#:none3 ##1order-pla?list#pla?list3 ##1set(#1c'rrent-id)#pla?list3#1position-o(-c'rrent#pla?list333
In order-pla?list, you c#n u!e the d#t#b#!e 'unction sort-rows to #ctu#lly per'or* the !ort, p#!!ing # li!t o' colu*n! to !ort by b#!ed on the ?#lue o' ordering.
1de('n#order-pla?list#1pla?list3 ##1appl?#NCsort-rows#1songs-table#pla?list3 ####1case#1ordering#pla?list3 ######1:genre##C1:genre#:alb'm#:trac&33
&he 'unction sh'((le-pla?list, c#lled by the Web inter'#ce code 6hen the u!er !elect! # ne6 !hu''le *ode, 6or9! in # !i*il#r '#!hion e.cept it doe!n@t need to ch#nge the ?#lue o' ordering. &hu!, 6hen sh'((le-pla?list i! c#lled 6ith # sh'((le o' :none, the pl#yli!t goe! b#c9 to being !orted #ccording to the *o!t recent ordering. Shu''ling by !ong! i! !i*ple--<u!t c#ll sh'((letable on songs-table. Shu''ling by #lbu*! i! # bit *ore in?ol?ed but !till not roc9et !cience.
1de('n#sh'((le-pla?list#1pla?list#sh'((le3 ##1set(#1sh'((le#pla?list3#sh'((le3 ##1case#sh'((le ####1:none#1order-pla?list#pla?list33 ####1:song#1sh'((le-b?-song#pla?list33 ####1:alb'm#1sh'((le-b?-alb'm#pla?list333 ##1set(#1c'rrent-id)#pla?list3#1position-o(-c'rrent#pla?list333 1de('n#sh'((le-b?-song#1pla?list3 ##1sh'((le-table#1songs-table#pla?list333 1de('n#sh'((le-b?-alb'm#1pla?list3 ##1let#11new-table#1ma&e-pla?list-table333 ####1do-rows#1alb'm-row#1sh'((led-alb'm-names#pla?list33 ######1do-rows#1song#1songs-(or-alb'm#pla?list#1col'mn-val'e#alb'm-row#:alb'm333 ########1insert-row#song#new-table333 ####1set(#1songs-table#pla?list3#new-table333 1de('n#sh'((led-alb'm-names#1pla?list3 ##1sh'((le-table# ###1select ####:col'mns#:alb'm ####:(rom#1songs-table#pla?list3 ####:distinct#t333 1de('n#songs-(or-alb'm#1pla?list#alb'm3 ##1select ###:(rom#1songs-table#pla?list3# ###:where#1matching#1songs-table#pla?list3#:alb'm#alb'm3 ###:order-b?#:trac&33
&he l#!t *#nipul#tion you need to !upport i! !etting the pl#yli!t@! repe#t *ode. 3o!t o' the ti*e you don@t need to t#9e #ny e.tr# #ction 6hen !etting repeat--it! ?#lue co*e! into pl#y only in ma?bemove-to-ne)t-song. >o6e?er, you need to upd#te the c'rrent-song #! # re!ult o' ch#nging repeat in one !itu#tion, n#*ely, i' c'rrent-id) i! #t the end o' # none*pty pl#yli!t #nd repeat i! being ch#nged to :song or :all. In th#t c#!e, you 6#nt to continue pl#ying, either repe#ting the l#!t !ong or !t#rting #t the beginning o' the pl#yli!t. So, you !hould de'ine #n :a(ter *ethod on the generic 'unction 1set(#repeat3.
1de(method#1set(#repeat3#:a(ter#1val'e#1pla?list#pla?list33 ##1i(#1and#1at-end-p#pla?list3#1not#1empt?-p#pla?list333 ####1ecase#val'e ######1:song#1set(#1c'rrent-id)#pla?list3#10-#1table-si*e#1songs-table# pla?list33333 ######1:none3 ######1:all##1set(#1c'rrent-id)#pla?list3# 333
####1'pdate-c'rrent-i(-necessar?#pla?list333
:o6 you h#?e #ll the underlying bit! you need. %ll th#t re*#in! i! the code th#t 6ill pro?ide # Webb#!ed u!er inter'#ce 'or bro6!ing the 3P3 d#t#b#!e #nd *#nipul#ting pl#yli!t!. &he inter'#ce 6ill con!i!t o' three *#in 'unction! de'ined 6ith de(ine-'rl-('nction: one 'or bro6!ing the !ong d#t#b#!e, one 'or ?ie6ing #nd *#nipul#ting # !ingle pl#yli!t, #nd one 'or li!ting #ll the #?#il#ble pl#yli!t!. 7ut be'ore you get to 6riting the!e three 'unction!, you need to !t#rt 6ith !o*e helper 'unction! #nd >&3 *#cro! th#t they@ll u!e.
&he l#!t string-/t?pe *ethod i! !lightly *ore co*ple.. /or re#!on! I@ll get to in # *o*ent, you@ll need to gener#te p#ge! th#t di!pl#y # 'or* th#t cont#in! # hidden 'ield 6ho!e ?#lue i! # li!t o' !tring!. Since you@re re!pon!ible 'or gener#ting the ?#lue in the hidden 'ield and 'or p#r!ing it 6hen it co*e! b#c9, you c#n u!e 6h#te?er encoding i! con?enient. 4ou could u!e the 'unction! WRITE-TO-STRING #nd READ-FROM-STRING, 6hich u!e the i!p printer #nd re#der to 6rite #nd re#d d#t# to #nd 'ro* !tring!, e.cept the printed repre!ent#tion o' !tring! c#n cont#in Fuot#tion *#r9! #nd other ch#r#cter! th#t *#y c#u!e proble*! 6hen e*bedded in the ?#lue #ttribute o' #n 98T+F ele*ent. So, you@ll need to e!c#pe tho!e ch#r#cter! !o*eho6. $#ther th#n trying to co*e up 6ith your o6n e!c#ping !che*e, you c#n <u!t u!e b#!e 0-, #n encoding co**only u!ed to protect bin#ry d#t# !ent through e-*#il. %llegroSer?e co*e! 6ith t6o 'unction!, base64-encode #nd base64-decode, th#t do the encoding #nd decoding 'or you, !o #ll you h#?e to do i! 6rite # p#ir o' 'unction!: one th#t encode! # i!p ob<ect by con?erting it to # re#d#ble !tring 6ith WRITE-TO-STRING #nd then b#!e 0- encoding it #nd, con?er!ely, #nother to decode !uch # !tring by b#!e 0- decoding it #nd p#!!ing the re!ult to READ-FROM-STRING. 4ou@ll 6#nt to 6r#p the c#ll! to WRITE-TO-STRING #nd READ-FROMSTRING in WITH-STANDARD-IO-SYNTAX to *#9e !ure #ll the ?#ri#ble! th#t #''ect the printer #nd re#der #re !et to their !t#nd#rd ?#lue!. >o6e?er, bec#u!e you@re going to be re#ding d#t# th#t@! co*ing in 'ro* the net6or9, you@ll de'initely 6#nt to turn o'' one 'e#ture o' the re#der--the #bility to e?#lu#te #rbitr#ry i!p code 6hile re#dingP- 4ou c#n de'ine your o6n *#cro with-sa(e-io-s?nta), 6hich 6r#p! it! body 'or*! in WITH-STANDARD-IO-SYNTAX 6r#pped #round # LET th#t bind! *READ-EVAL* to NIL.
1de(macro#with-sa(e-io-s?nta)#1>bod?#bod?3 ##B1with-standard-io-s?nta) #####1let#11Uread-evalU#nil33 #######5Pbod?333
/in#lly, you c#n u!e the!e 'unction! to de'ine # *ethod on string-/t?pe th#t de'ine! the con?er!ion 'or the Fuery p#r#*eter type base64-list.
1de(method#string-/t?pe#11t?pe#1e@l#Cbase-64-list33#val'e3 ##1let#11obj#1base64-/obj#val'e333 ####1i(#1listp#obj3#obj#nil333
Boi%erp%ate .T+L
:e.t you need to de'ine !o*e >&3 *#cro! #nd helper 'unction! to *#9e it e#!y to gi?e the di''erent p#ge! in the #pplic#tion # con!i!tent loo9 #nd 'eel. 4ou c#n !t#rt 6ith #n >&3 *#cro th#t de'ine! the b#!ic !tructure o' # p#ge in the #pplic#tion.
1de(ine-html-macro#:mp3-browser-page#11>&e?#title#1header#title33#>bod?#bod?3 ##B1:html #####1:head ######1:title#5title3 ######1:lin&#:rel#4st?lesheet4#:t?pe#4te)t/css4#:hre(#4mp3-browser.css433 #####1:bod? ######1standard-header3 ######1when#5header#1html#1:h0#:class#4title4#5header333 ######5Pbod? ######1standard-(ooter3333
4ou !hould de'ine standard-header #nd standard-(ooter #! !ep#r#te 'unction! 'or t6o re#!on!. /ir!t, during de?elop*ent you c#n rede'ine tho!e 'unction! #nd !ee the e''ect i**edi#tely 6ithout h#?ing to reco*pile 'unction! th#t u!e the :mp3-browser-page *#cro. Second, it turn! out th#t one o' the p#ge! you@ll 6rite l#ter 6on@t be de'ined 6ith :mp3-browser-page but 6ill !till need the !t#nd#rd he#der #nd 'ooter!. &hey loo9 li9e thi!:
1de(parameter#UrU#!"3 1de('n#standard-header#13 ##1html ###11:p#:class#4toolbar43 ####4D4#1:a#:hre(#1lin/browse4#:what#4genre43#4Ill#genres43#4G#4 ####4D4#1:a#:hre(#1lin/browse4#:what#4genre4#:random#UrU3#4.andom#genres43#4G#4 ####4D4#1:a#:hre(#1lin/browse4#:what#4artist43#4Ill#artists43#4G#4 ####4D4#1:a#:hre(#1lin/browse4#:what#4artist4#:random#UrU3#4.andom#artists43#4G# 4 ####4D4#1:a#:hre(#1lin/browse4#:what#4alb'm43#4Ill#alb'ms43#4G#4 ####4D4#1:a#:hre(#1lin/browse4#:what#4alb'm4#:random#UrU3#4.andom#alb'ms43#4G#4 ####4D4#1:a#:hre(#1lin/browse4#:what#4song4#:random#UrU3#4.andom#songs43#4G#4 ####4D4#1:a#:hre(#1lin/pla?list43#4Tla?list43#4G#4 ####4D4#1:a#:hre(#1lin/all-pla?lists43#4Ill#pla?lists43#4G4333 1de('n#standard-(ooter#13
##1html#1:hr3#11:p#:class#4(ooter43#4%T3#Lrowser#v4#Umajor-versionU#4.4#UminorversionU333
% couple o' !*#ller >&3 *#cro! #nd helper 'unction! #uto*#te other co**on p#ttern!. &he :table-row >&3 *#cro *#9e! it e#!ier to gener#te the >&3 'or # !ingle ro6 o' # t#ble. It u!e! # 'e#ture o' /55 th#t I@ll di!cu!! in Ch#pter 31, #n >attrib'tes p#r#*eter, 6hich c#u!e! u!e! o' the *#cro to be p#r!ed <u!t li9e nor*#l !-e.pre!!ion >&3 'or*!, 6ith #ny #ttribute! g#thered into # li!t th#t 6ill be bound to the >attrib'tes p#r#*eter. It loo9! li9e thi!:
1de(ine-html-macro#:table-row#1>attrib'tes#attrs#>rest#val'es3 ##B1:tr#5Pattrs#5P1loop#(or#v#in#val'es#collect#B1:td#5v3333
%nd the lin& 'unction gener#te! # 8$ b#c9 into the #pplic#tion to be u!ed #! the :.-E #ttribute 6ith #n I ele*ent, building # Fuery !tring out o' # !et o' 9ey6ord;?#lue p#ir! #nd *#9ing !ure #ll !peci#l ch#r#cter! #re properly e!c#ped. /or in!t#nce, in!te#d o' 6riting thi!:
1:a#:hre(#4browse?what=artist>genre=.h?thm26!62Ll'es4#4Irtists43
&o 8$ encode the 9ey! #nd ?#lue!, you u!e the helper 'unction 'rlencode, 6hich i! # 6r#pper #round the 'unction encode-(orm-'rlencoded, 6hich i! # nonpublic 'unction 'ro* %llegroSer?e. &hi! i!--on one h#nd--b#d 'or*G !ince the n#*e encode-(orm-'rlencoded i!n@t e.ported 'ro* 8-F.I,-.K-, it@! po!!ible th#t encode-(orm-'rlencoded *#y go #6#y or get ren#*ed out 'ro* under you. 5n the other h#nd, u!ing thi! une.ported !y*bol 'or the ti*e being let! you get 6or9 done 'or the *o*entG by 6r#pping encode-(orm-'rlencoded in your o6n 'unction, you i!ol#te the cru'ty code to one 'unction, 6hich you could re6rite i' you h#d to.
1de('n#'rlencode#1string3 ##1net.aserve::encode-(orm-'rlencoded#string33
/in#lly, you need the CSS !tyle !heet mp3-browser.css u!ed by :mp3-browser-page. Since there@! nothing dyn#*ic #bout it, it@! prob#bly e#!ie!t to <u!t publi!h # !t#tic 'ile 6ith p'blish-(ile.
1p'blish-(ile#:path#4/mp3-browser.css4##:(ile#filename#:content-t?pe#4te)t/css43
% !#*ple !tyle !heet i! included 6ith the !ource code 'or thi! ch#pter on the boo9@! Web !ite. 4ou@ll de'ine # 'unction, #t the end o' thi! ch#pter, th#t !t#rt! the 3P3 bro6!er #pplic#tion. It@ll t#9e c#re o', #*ong other thing!, publi!hing thi! 'ile.
they@re intere!ted in. It@ll gi?e the* # 6#y to !elect d#t#b#!e entrie! th#t *#tch # !peci'ic genre, #rti!t, or #lbu*. In the intere!t o' !erendipity, you c#n #l!o pro?ide # 6#y to !elect # r#ndo* !ub!et o' *#tching ite*!. When the u!er i! bro6!ing #t the le?el o' indi?idu#l !ong!, the title o' the !ong 6ill be # lin9 th#t c#u!e! th#t !ong to be #dded to the pl#yli!t. 5ther6i!e, e#ch ite* 6ill be pre!ented 6ith lin9! th#t let the u!er bro6!e the li!ted ite* by !o*e other c#tegory. /or e.#*ple, i' the u!er i! bro6!ing genre!, the entry H7lue!H 6ill cont#in lin9! to bro6!e #ll #lbu*!, #rti!t!, #nd !ong! in the genre 7lue!. %ddition#lly, the bro6!e p#ge 6ill 'e#ture #n H%dd #llH button th#t #dd! e?ery !ong *#tching the p#ge@! criteri# to the u!er@! pl#yli!t. &he 'unction loo9! li9e thi!:
1de(ine-'rl-('nction#browse ####1re@'est#1what#&e?word#:genre3#genre#artist#alb'm#1random#integer33 ##1letU#11val'es#1val'es-(or-page#what#genre#artist#alb'm#random33 #########1title#1browse-page-title#what#random#genre#artist#alb'm33 #########1single-col'mn#1i(#1e@l#what#:song3#:(ile#what33 #########1val'es-string#1val'es-/base-64#single-col'mn#val'es333 ####1html #####1:mp3-browser-page ######1:title#title3 ######11:(orm#:method#4T;,F4#:action#4pla?list43 #######1:inp't#:name#4val'es4#:t?pe#4hidden4#:val'e#val'es-string3 #######1:inp't#:name#4what4#:t?pe#4hidden4#:val'e#single-col'mn3 #######1:inp't#:name#4action4#:t?pe#4hidden4#:val'e#:add-songs3 #######1:inp't#:name#4s'bmit4#:t?pe#4s'bmit4#:val'e#4Idd#all433 ######1:'l#1do-rows#1row#val'es3#1list-item-(or-page#what#row3333333
&hi! 'unction !t#rt! by u!ing the 'unction val'es-(or-page to get # t#ble cont#ining the ?#lue! it need! to pre!ent. When the u!er i! bro6!ing by !ong--6hen the what p#r#*eter i! :song--you 6#nt to !elect co*plete ro6! 'ro* the d#t#b#!e. 7ut 6hen they@re bro6!ing by genre, #rti!t, or #lbu*, you 6#nt to !elect only the di!tinct ?#lue! 'or the gi?en c#tegory. &he d#t#b#!e 'unction select doe! *o!t o' the he#?y li'ting, 6ith val'es-(or-page *o!tly re!pon!ible 'or p#!!ing the right #rgu*ent! depending on the ?#lue o' what. &hi! i! #l!o 6here you !elect # r#ndo* !ub!et o' the *#tching ro6! i' nece!!#ry.
1de('n#val'es-(or-page#1what#genre#artist#alb'm#random3 ##1let#11val'es #########1select# ##########:(rom#Ump3sU ##########:col'mns#1i(#1e@l#what#:song3#t#what3 ##########:where#1matching#Ump3sU#:genre#genre#:artist#artist#:alb'm#alb'm3 ##########:distinct#1not#1e@l#what#:song33 ##########:order-b?#1i(#1e@l#what#:song3#C1:alb'm#:trac&3#what3333 ####1i(#random#1random-selection#val'es#random3#val'es333
&o gener#te the title 'or the bro6!e p#ge, you p#!! the bro6!ing criteri# to the 'ollo6ing 'unction, browse-page-title:
1de('n#browse-page-title#1what#random#genre#artist#alb'm3 ##1with-o'tp't-to-string#1s3 ####1when#random#1(ormat#s#47:17r73#.andom#4#random33 ####1(ormat#s#47:17a7p734#what#random3 ####1when#1or#genre#artist#alb'm3 ######1when#1not#1e@l#what#:song33#1princ#4#with#songs4#s33 ######1when#genre##1(ormat#s#4#in#genre#7a4#genre33 ######1when#artist#1(ormat#s#4#b?#artist#7a#4#artist33 ######1when#alb'm##1(ormat#s#4#on#alb'm#7a4#alb'm33333
5nce you h#?e the ?#lue! you 6#nt to pre!ent, you need to do t6o thing! 6ith the*. &he *#in t#!9, o' cour!e, i! to pre!ent the*, 6hich h#ppen! in the do-rows loop, le#?ing the rendering o' e#ch ro6 to the 'unction list-item-(or-page. &h#t 'unction render! :song ro6! one 6#y #nd #ll other 9ind! #nother 6#y.
1de('n#list-item-(or-page#1what#row3 ##1i(#1e@l#what#:song3 ####1with-col'mn-val'es#1song#(ile#alb'm#artist#genre3#row ######1html ########1:li #########1:a#:hre(#1linpla?list4#:(ile#(ile#:action#4add-songs43#1:b#song33#4# (rom#4 #########1:a#:hre(#1linbrowse4##:what#:song#:alb'm##alb'm3#alb'm3#4#b?#4 #########1:a#:hre(#1linbrowse4#:what#:song#:artist#artist3#artist3#4#in#genre#4 #########1:a#:hre(#1linbrowse4##:what#:song#:genre##genre3#genre3333 ####1let#11val'e#1col'mn-val'e#row#what333 ######1html #######1:li#val'e#4#-#4 ############1browse-lin&#:genre##what#val'e3 ############1browse-lin&#:artist#what#val'e3 ############1browse-lin&#:alb'm##what#val'e3 ############1browse-lin&#:song###what#val'e333333 1de('n#browse-linnew-what#what#val'e3 ##1'nless#1e@l#new-what#what3 ####1html #####4D4# #####1:a#:hre(#1linbrowse4#:what#new-what#what#val'e3#1:(ormat#4717as734#newwhat33 #####4G#4333
&he other thing on the browse p#ge i! # 'or* 6ith !e?er#l hidden 98T+F 'ield! #nd #n H%dd #llH !ub*it button. 4ou need to u!e #n >&3 'or* in!te#d o' # regul#r lin9 to 9eep the #pplic#tion !t#tele!!--to *#9e !ure #ll the in'or*#tion needed to re!pond to # reFue!t co*e! in the reFue!t it!el'. 7ec#u!e the bro6!e p#ge re!ult! c#n be p#rti#lly r#ndo*, you need to !ub*it # '#ir bit o' d#t# 'or the !er?er to be #ble to recon!titute the li!t o' !ong! to #dd to the pl#yli!t. I' you didn@t #llo6 the bro6!e p#ge to return r#ndo*ly gener#ted re!ult!, you 6ouldn@t need *uch d#t#--you could <u!t !ub*it # reFue!t to #dd !ong! 6ith 6h#te?er !e#rch criteri# the bro6!e p#ge u!ed. 7ut i' you #dded !ong! th#t 6#y, 6ith criteri# th#t included # random #rgu*ent, then you@d end up #dding # di''erent !et o' r#ndo* !ong! th#n the u!er 6#! loo9ing #t on the p#ge 6hen they hit the H%dd #llH button. &he !olution you@ll u!e i! to !end b#c9 # 'or* th#t h#! enough in'or*#tion !t#!hed #6#y in # hidden 98T+F ele*ent to #llo6 the !er?er to recon!titute the li!t o' !ong! *#tching the bro6!e p#ge criteri#. &h#t in'or*#tion i! the li!t o' ?#lue! returned by val'es-(or-page #nd the ?#lue o' the what p#r#*eter. &hi! i! 6here you u!e the base64-list p#r#*eter typeG the 'unction val'es/base64 e.tr#ct! the ?#lue! o' # !peci'ied colu*n 'ro* the t#ble returned by val'es-(or-page into # li!t #nd then *#9e! # b#!e 0--encoded !tring out o' th#t li!t to e*bed in the 'or*.
1de('n#val'es-/base-64#1col'mn#val'es-table3 ##1(let#11val'e#1r3#1col'mn-val'e#r#col'mn333 ####1obj-/base64#1map-rows#NCval'e#val'es-table3333
When th#t p#r#*eter co*e! b#c9 #! the ?#lue o' the val'es Fuery p#r#*eter to # 8$ 'unction th#t decl#re! val'es to be o' type base-64-list, it@ll be #uto*#tic#lly con?erted b#c9 to # li!t. %! you@ll !ee in # *o*ent, th#t li!t c#n then be u!ed to con!truct # Fuery th#t@ll return the correct li!t o'
!ong!.5 When you@re bro6!ing by :song, you u!e the ?#lue! 'ro* the :(ile colu*n !ince they uniFuely identi'y the #ctu#l !ong! 6hile the !ong n#*e! *#y not.
The "%ay%ist
&hi! bring! *e to the ne.t 8$ 'unction, pla?list. &hi! i! the *o!t co*ple. p#ge o' the three--it@! re!pon!ible 'or di!pl#ying the current content! o' the u!er@! pl#yli!t #! 6ell #! 'or pro?iding the inter'#ce to *#nipul#te the pl#yli!t. 7ut 6ith *o!t o' the tediou! boo99eeping h#ndled by de(ine'rl-('nction, it@! not too h#rd to !ee ho6 pla?list 6or9!. >ere@! the beginning o' the de'inition, 6ith <u!t the p#r#*eter li!t:
1de(ine-'rl-('nction#pla?list# ####1re@'est #####1pla?list-id#string#1pla?list-id#re@'est3#:pac&age3 #####1action#&e?word3######S#Tla?list#manip'lation#action #####1what#&e?word#:(ile3##S#(or#:add-songs#action #####1val'es#base-64-list3#S#############4 #####(ile##################S#(or#:add-songs#and#:delete-songs#actions #####genre#################S#(or#:delete-songs#action #####artist################S#############4 #####alb'm#################S#############4 #####1order-b?#&e?word3####S#(or#:sort#action #####1sh'((le#&e?word3#####S#(or#:sh'((le#action #####1repeat#&e?word33#####S#(or#:set-repeat#action
In #ddition to the oblig#tory re@'est p#r#*eter, pla?list t#9e! # nu*ber o' Fuery p#r#*eter!. &he *o!t i*port#nt in !o*e 6#y! i! pla?list-id, 6hich identi'ie! 6hich pla?list ob<ect the p#ge !hould di!pl#y #nd *#nipul#te. /or thi! p#r#*eter, you c#n t#9e #d?#nt#ge o' de(ine-'rl('nction@! H!tic9y p#r#*eterH 'e#ture. :or*#lly, the pla?list-id 6on@t be !upplied e.plicitly, de'#ulting to the ?#lue returned by the pla?list-id 'unction, n#*ely, the IP #ddre!! o' the client *#chine on 6hich the bro6!er i! running. >o6e?er, u!er! c#n #l!o *#nipul#te their pl#yli!t! 'ro* di''erent *#chine! th#n the one! running their 3P3 client! by #llo6ing thi! ?#lue to be e.plicitly !peci'ied. %nd i' it@! !peci'ied once, de(ine-'rl-('nction 6ill #rr#nge 'or it to H!tic9H by !etting # coo9ie in the bro6!er. #ter you@ll de'ine # 8$ 'unction th#t gener#te! # li!t o' #ll e.i!ting pl#yli!t!, 6hich u!er! c#n u!e to pic9 # pl#yli!t other th#n the one 'or the *#chine! they@re bro6!ing 'ro*. &he action p#r#*eter !peci'ie! !o*e #ction to t#9e on the u!er@! pl#yli!t ob<ect. &he ?#lue o' thi! p#r#*eter, 6hich 6ill be con?erted to # 9ey6ord !y*bol 'or you, c#n be :add-songs, :deletesongs, :clear, :sort, :sh'((le, or :set-repeat. &he :add-songs #ction i! u!ed by the H%dd #llH button in the bro6!e p#ge #nd #l!o by the lin9! u!ed to #dd indi?idu#l !ong!. &he other #ction! #re u!ed by the lin9! on the pl#yli!t p#ge it!el'. &he (ile, what, #nd val'es p#r#*eter! #re u!ed 6ith the :add-songs #ction. 7y decl#ring val'es to be o' type base-64-list, the de(ine-'rl-('nction in'r#!tructure 6ill t#9e c#re o' decoding the ?#lue !ub*itted by the H%dd #llH 'or*. &he other p#r#*eter! #re u!ed 6ith other #ction! #! noted in the co**ent!. :o6 let@! loo9 #t the body o' pla?list. &he 'ir!t thing you need to do i! u!e the pla?list-id to loo9 up the Fueue ob<ect #nd then #cFuire the pl#yli!t@! loc9 6ith the 'ollo6ing t6o line!:
1let#11pla?list#1loo&'p-pla?list#pla?list-id333 ##1with-pla?list-loc&ed#1pla?list3
Since loo&'p-pla?list 6ill cre#te # ne6 pl#yli!t i' nece!!#ry, thi! 6ill #l6#y! return # pla?list ob<ect. &hen you t#9e c#re o' #ny nece!!#ry Fueue *#nipul#tion, di!p#tching on the ?#lue o' the action p#r#*eter in order to c#ll one o' the pla?list 'unction!.
1case#action ##1:add-songs######1add-songs#pla?list#what#1or#val'es#1list#(ile3333 ##1:delete-songs###1delete-songs# ####################pla?list# ####################:(ile#(ile#:genre#genre ####################:artist#artist#:alb'm#alb'm33 ##1:clear##########1clear-pla?list#pla?list33 ##1:sort###########1sort-pla?list#pla?list#order-b?33 ##1:sh'((le########1sh'((le-pla?list#pla?list#sh'((le33 ##1:set-repeat#####1set(#1repeat#pla?list3#repeat333
%ll th#t@! le't o' the pla?list 'unction i! the #ctu#l >&3 gener#tion. %g#in, you c#n u!e the :mp3-browser-page >&3 *#cro to *#9e !ure the b#!ic 'or* o' the p#ge *#tche! the other p#ge! in the #pplic#tion, though thi! ti*e you p#!! NIL to the :header #rgu*ent in order to le#?e out the :0 he#der. >ere@! the re!t o' the 'unction:
1html #1:mp3-browser-page ##1:title#1:(ormat#4Tla?list#-#7a4#1id#pla?list33#:header#nil3 ##1pla?list-toolbar#pla?list3 ##1i(#1empt?-p#pla?list3 ####1html#1:p#1:i#4-mpt?.4333 ####1html# ######11:table#:class#4pla?list43 #######1:table-row#4N4#4,ong4#4Ilb'm4#4Irtist4#4Jenre43 #######1let#11id)# 3 #############1c'rrent-id)#1c'rrent-id)#pla?list333 #########1do-rows#1row#1songs-table#pla?list33 ###########1with-col'mn-val'es#1trac&#(ile#song#alb'm#artist#genre3#row #############1let#11row-st?le#1i(#1=#id)#c'rrent-id)3#4now-pla?ing4#4normal4333 ###############1html #################11:table-row#:class#row-st?le3 ##################trac& ##################1:progn#song###1delete-songs-lin&#:(ile#(ile33 ##################1:progn#alb'm##1delete-songs-lin&#:alb'm#alb'm33 ##################1:progn#artist#1delete-songs-lin&#:artist#artist33 ##################1:progn#genre##1delete-songs-lin&#:genre#genre33333 #############1inc(#id)333333333333
&he 'unction pla?list-toolbar gener#te! # toolb#r cont#ining lin9! to pla?list to per'or* the ?#riou! :action *#nipul#tion!. %nd delete-songs-lin& gener#te! # lin9 to pla?list 6ith the :action p#r#*eter !et to :delete-songs #nd the #ppropri#te #rgu*ent! to delete #n indi?idu#l 'ile, or #ll 'ile! on #n #lbu*, by # p#rticul#r #rti!t or in # !peci'ic genre.
1de('n#pla?list-toolbar#1pla?list3 ##1let#11c'rrent-repeat#1repeat#pla?list33 ########1c'rrent-sort#1ordering#pla?list33 ########1c'rrent-sh'((le#1sh'((le#pla?list333 ####1html #####1:p#:class#4pla?list-toolbar4 #########1:i#4,ort#b?:43 #########4#D#4 #########1sort-pla?list-b'tton#4genre4#c'rrent-sort3#4#X#4#
#########1sort-pla?list-b'tton#4artist4#c'rrent-sort3#4#X#4# #########1sort-pla?list-b'tton#4alb'm4#c'rrent-sort3#4#X#4# #########1sort-pla?list-b'tton#4song4#c'rrent-sort3#4#G#4 #########1:i#4,h'((le#b?:43 #########4#D#4 #########1pla?list-sh'((le-b'tton#4none4#c'rrent-sh'((le3#4#X#4 #########1pla?list-sh'((le-b'tton#4song4#c'rrent-sh'((le3#4#X#4 #########1pla?list-sh'((le-b'tton#4alb'm4#c'rrent-sh'((le3#4#G#4 #########1:i#4.epeat:43 #########4#D#4 #########1pla?list-repeat-b'tton#4none4#c'rrent-repeat3#4#X#4 #########1pla?list-repeat-b'tton#4song4#c'rrent-repeat3#4#X#4 #########1pla?list-repeat-b'tton#4all4#c'rrent-repeat3#4#G#4 #########4D#4#1:a#:hre(#1linpla?list4#:action#4clear43#4$lear43#4#G#43333 1de('n#pla?list-b'tton#1action#arg'ment#new-val'e#c'rrent-val'e3 ##1let#11label#1string-capitali*e#new-val'e333 ####1i(#1string-e@'al#new-val'e#c'rrent-val'e3 ######1html#1:b#label33 ######1html#1:a#:hre(#1linpla?list4#:action#action#arg'ment#new-val'e3# label33333 1de('n#sort-pla?list-b'tton#1order-b?#c'rrent-sort3 ##1pla?list-b'tton#:sort#:order-b?#order-b?#c'rrent-sort33 1de('n#pla?list-sh'((le-b'tton#1sh'((le#c'rrent-sh'((le3 ##1pla?list-b'tton#:sh'((le#:sh'((le#sh'((le#c'rrent-sh'((le33 1de('n#pla?list-repeat-b'tton#1repeat#c'rrent-repeat3 ##1pla?list-b'tton#:set-repeat#:repeat#repeat#c'rrent-repeat33 1de('n#delete-songs-linwhat#val'e3 ##1html#4#D4#1:a#:hre(#1linpla?list4#:action#:delete-songs#what#val'e3#4)43# 4G433
Finding a "%ay%ist
&he l#!t o' the three 8$ 'unction! i! the !i*ple!t. It pre!ent! # t#ble li!ting #ll the pl#yli!t! th#t h#?e been cre#ted. 5rdin#rily u!er! 6on@t need to u!e thi! p#ge, but during de?elop*ent it gi?e! you # u!e'ul ?ie6 into the !t#te o' the !y!te*. It #l!o pro?ide! the *ech#ni!* to choo!e # di''erent pl#yli!t--e#ch pl#yli!t I+ i! # lin9 to the pla?list p#ge 6ith #n e.plicit pla?list-id Fuery p#r#*eter, 6hich 6ill then be *#de !tic9y by the pla?list 8$ 'unction. :ote th#t you need to #cFuire the Upla?lists-loc&U to *#9e !ure the Upla?listsU h#!h t#ble doe!n@t ch#nge out 'ro* under you 6hile you@re iter#ting o?er it.
1de(ine-'rl-('nction#all-pla?lists#1re@'est3 ##1:mp3-browser-page ###1:title#4Ill#Tla?lists43 ###11:table#:class#4all-pla?lists43 ####1:table-row#4Tla?list4#4N#,ongs4#4%ost#recent#'ser#agent43 ####1with-process-locUpla?lists-loc&U3 ######1loop#(or#pla?list#being#the#hash-val'es#o(#Upla?listsU#do ###########1html #############1:table-row ##############1:a#:hre(#1linpla?list4#:pla?list-id#1id#pla?list33#1:print#1id#
When you in?o9e thi! 'unction, it 6ill print dot! 6hile it lo#d! the I+3 in'or*#tion 'ro* your I+3 'ile!. &hen you c#n point your 3P3 client #t thi! 8$ :
http://localhost:! 0/stream.mp3
#nd point your bro6!er #t !o*e good !t#rting pl#ce, !uch #! thi!:
http://localhost:! 0/browse
6hich 6ill let you !t#rt bro6!ing by the de'#ult c#tegory, =enre. %'ter you@?e #dded !o*e !ong! to the pl#yli!t, you c#n pre!! Pl#y on the 3P3 client, #nd it !hould !t#rt pl#ying the 'ir!t !ong. 5b?iou!ly, you could i*pro?e the u!er inter'#ce in #ny o' # nu*ber o' 6#y!--'or in!t#nce, i' you h#?e # lot o' 3P3! in your libr#ry, it *ight be u!e'ul to be #ble to bro6!e #rti!t! or #lbu*! by the 'ir!t letter o' their n#*e!. 5r *#ybe you could #dd # HPl#y 6hole #lbu*H button to the pl#yli!t p#ge th#t c#u!e! the pl#yli!t to i**edi#tely put #ll the !ong! 'ro* the !#*e #lbu* #! the currently pl#ying !ong #t the top o' the pl#yli!t. 5r you could ch#nge the pla?list cl#!!, !o in!te#d o' pl#ying !ilence 6hen there #re no !ong! Fueued up, it pic9! # r#ndo* !ong 'ro* the d#t#b#!e. 7ut #ll tho!e ide#! '#ll in the re#l* o' #pplic#tion de!ign, 6hich i!n@t re#lly the topic o' thi! boo9. In!te#d, the ne.t t6o ch#pter! 6ill drop b#c9 to the le?el o' !o't6#re in'r#!tructure to co?er ho6 the /55 >&3 gener#tion libr#ry 6or9!.
1&he
intric#cie! o' concurrent progr#**ing #re beyond the !cope o' thi! boo9. &he b#!ic ide# i! th#t i' you h#?e *ultiple thre#d! o' control--#! you 6ill in thi! #pplic#tion 6ith !o*e thre#d! running the sho'tcast 'unction #nd other thre#d! re!ponding to reFue!t! 'ro* the bro6!er--then you need to *#9e !ure only one thre#d #t # ti*e *#nipul#te! #n ob<ect in order to pre?ent one thre#d 'ro* !eeing the ob<ect in #n incon!i!tent !t#te 6hile #nother thre#d i! 6or9ing on it. In thi! 'unction, 'or in!t#nce, i'
t6o ne6 3P3 client! #re connecting #t the !#*e ti*e, they@d both try to #dd #n entry to Upla?listsU #nd *ight inter'ere 6ith e#ch other. &he with-process-loc& en!ure! th#t e#ch thre#d get! e.clu!i?e #cce!! to the h#!h t#ble 'or long enough to do the 6or9 it need! to do.
2&hi!
#ppro#ch #l!o #!!u*e! th#t e?ery client *#chine h#! # uniFue IP #ddre!!. &hi! #!!u*ption !hould hold #! long #! #ll the u!er! #re on the !#*e %: but *#y not hold i' client! #re connecting 'ro* behind # 'ire6#ll th#t doe! net6or9 #ddre!! tr#n!l#tion. +eploying thi! #pplic#tion out!ide # %: 6ill reFuire !o*e *odi'ic#tion!, but i' you 6#nt to deploy thi! #pplic#tion to the 6ider Internet, you@d better 9no6 enough #bout net6or9ing to 'igure out #n #ppropri#te !che*e your!el'.
38n'ortun#tely,
bec#u!e o' licen!ing i!!ue! #round the 3P3 'or*#t, it@! not cle#r th#t it@! leg#l 'or *e to pro?ide you 6ith !uch #n 3P3 6ithout p#ying licen!ing 'ee! to /r#unho'er IIS. I got *ine #! p#rt o' the !o't6#re th#t c#*e 6ith *y Sli*p3 'ro* Sli* +e?ice!. 4ou c#n gr#b it 'ro* their Sub?er!ion repo!itory ?i# the Web #t http://svn.slimdevices.com/Uchec&o'tU/tr'n&/server/# :FML0EN06!8%0("%'#! $<)'!=8 >?&'7=9. 5r buy # SFueeAebo., the ne6, 6irele!! ?er!ion o' Sli*p3, #nd you@ll get silentpac&et.mp3 #! p#rt o' the !o't6#re th#t co*e! 6ith it. 5r 'ind #n 3P3 o' Dohn C#ge@! piece 9(FFG.
-&he
re#der !upport! # bit o' !ynt#., N., th#t c#u!e! the 'ollo6ing !-e.pre!!ion to be e?#lu#ted #t re#d ti*e. &hi! i! occ#!ion#lly u!e'ul in !ource code but ob?iou!ly open! # big !ecurity hole 6hen you re#d untru!ted d#t#. >o6e?er, you c#n turn o'' thi! !ynt#. by !etting *READ-EVAL* to NIL, 6hich 6ill c#u!e the re#der to !ign#l #n error i' it encounter! N..
5&hi!
!olution h#! it! dr#6b#c9!--i' # browse p#ge return! # lot o' re!ult!, # '#ir bit o' d#t# i! going b#c9 #nd 'orth under the co?er!. %l!o, the d#t#b#!e Fuerie! #ren@t nece!!#rily the *o!t e''icient. 7ut it doe! 9eep the #pplic#tion !t#tele!!. %n #ltern#ti?e #ppro#ch i! to !Fuirrel #6#y, on the !er?er !ide, in'or*#tion #bout the re!ult! returned by browse #nd then, 6hen # reFue!t to #dd !ong! co*e in, 'ind the #ppropri#te bit o' in'or*#tion in order to re-cre#te the correct !et o' !ong!. /or in!t#nce, you could <u!t !#?e the ?#lue! li!t in!te#d o' !ending it b#c9 in the 'or*. 5r you could copy the RANDOM-STATE ob<ect be'ore you gener#te the bro6!e re!ult! !o you c#n l#ter re-cre#te the !#*e Hr#ndo*H re!ult!. 7ut thi! #ppro#ch c#u!e! it! o6n proble*!. /or in!t#nce, you@d then need to 6orry #bout 6hen you c#n get rid o' the !Fuirreled-#6#y in'or*#tionG you ne?er 9no6 6hen the u!er *ight hit the 7#c9 button on their bro6!er to return to #n old bro6!e p#ge #nd then hit the H%dd #llH button. Welco*e to the 6onder'ul 6orld o' Web progr#**ing.
&hi! Hl#ngu#geH i! highly e.pre!!i?e !ince it c#n e.pre!! an0 >&3 you could po!!ibly 6#nt to gener#te.1 5n the other h#nd, thi! l#ngu#ge doe!n@t 6in # lot o' point! 'or it! conci!ion bec#u!e it gi?e! you Aero co*pre!!ion--it! input is it! output. &o de!ign # l#ngu#ge th#t gi?e! you !o*e u!e'ul co*pre!!ion 6ithout !#cri'icing too *uch e.pre!!i?ene!!, you need to identi'y the det#il! o' the output th#t #re either redund#nt or unintere!ting. 4ou c#n then *#9e tho!e #!pect! o' the output i*plicit in the !e*#ntic! o' the l#ngu#ge. /or in!t#nce, bec#u!e o' the !tructure o' >&3 , e?ery opening t#g i! p#ired 6ith # *#tching clo!ing t#g.2 When you 6rite >&3 by h#nd, you h#?e to 6rite tho!e clo!ing t#g!, but you c#n i*pro?e the conci!ion o' your >&3 -gener#ting l#ngu#ge by *#9ing the clo!ing t#g! i*plicit. %nother 6#y you c#n g#in conci!ion #t # !light co!t in e.pre!!i?ene!! i! to *#9e the l#ngu#ge proce!!or! re!pon!ible 'or #dding #ppropri#te 6hite!p#ce bet6een ele*ent!--bl#n9 line! #nd indent#tion. When you@re gener#ting >&3 progr#**#tic#lly, you typic#lly don@t c#re *uch #bout 6hich ele*ent! h#?e line bre#9! be'ore or #'ter the* or #bout 6hether di''erent ele*ent! #re indented rel#ti?e to their p#rent ele*ent!. etting the l#ngu#ge proce!!or in!ert 6hite!p#ce #ccording to !o*e rule *e#n! you don@t h#?e to 6orry #bout it. %! it turn! out, /55 #ctu#lly !upport! t6o *ode!--one th#t u!e! the *ini*u* #*ount o' 6hite!p#ce, 6hich #llo6! it to gener#te e.tre*ely e''icient code #nd co*p#ct >&3 , #nd #nother th#t gener#te! nicely 'or*#tted >&3 6ith di''erent ele*ent! indented #nd !ep#r#ted 'ro* other ele*ent! #ccording to their role. %nother det#il th#t@! be!t *o?ed into the l#ngu#ge proce!!or i! the e!c#ping o' cert#in ch#r#cter! th#t h#?e # !peci#l *e#ning in >&3 !uch #! O, /, #nd >. 5b?iou!ly, i' you gener#te >&3 by <u!t printing !tring! to # !tre#*, then it@! up to you to repl#ce #ny occurrence! o' tho!e ch#r#cter! in the !tring 6ith the #ppropri#te e!c#pe !eFuence!, >ltS, >gtS #nd >ampS. 7ut i' the l#ngu#ge proce!!or c#n 9no6 6hich !tring! #re to be e*itted #! ele*ent d#t#, then it c#n t#9e c#re o' #uto*#tic#lly e!c#ping tho!e ch#r#cter! 'or you.
5b<ect! th#t !#ti!'y thi! predic#te 6ill be e*itted by con?erting the* to !tring! 6ith PRINC-TOSTRING #nd then e!c#ping #ny re!er?ed ch#r#cter!, !uch #! O, /, or >. When the ?#lue i! being e*itted #! #n #ttribute, the ch#r#cter! 4, #nd C #re #l!o e!c#ped. &hu!, you c#n in?o9e the html *#cro
on # !el'-e?#lu#ting ob<ect to e*it it to Uhtml-o'tp'tU B6hich i! initi#lly bound to *STANDARDOUTPUT*C. &#ble 30-1 !ho6! ho6 # 'e6 di''erent !el'-e?#lu#ting ?#lue! 6ill be output. &#ble 30-1. /55 5utput 'or Sel'-(?#lu#ting 5b<ect! /55 /or* =ener#ted >&3 4(oo4 (oo 0 0 :(oo E;; 4(oo#>#bar4 (oo#>ampS#bar 5' cour!e, *o!t >&3 con!i!t! o' t#gged ele*ent!. &he three piece! o' in'or*#tion th#t de!cribe e#ch ele*ent #re the t#g, # !et o' #ttribute!, #nd # body cont#ining te.t #nd;or *ore >&3 ele*ent!. &hu!, you need # 6#y to repre!ent the!e three piece! o' in'or*#tion #! i!p ob<ect!, pre'er#bly one! th#t the i!p re#der #lre#dy 9no6! ho6 to re#d.- I' you 'orget #bout #ttribute! 'or # *o*ent, there@! #n ob?iou! *#pping bet6een i!p li!t! #nd >&3 ele*ent!: #ny >&3 ele*ent c#n be repre!ented by # li!t 6ho!e FIRST i! # !y*bol 6here the n#*e i! the n#*e o' the ele*ent@! t#g #nd 6ho!e REST i! # li!t o' !el'-e?#lu#ting ob<ect! or li!t! repre!enting other >&3 ele*ent!. &hu!:
Op/EooO/p/#O==/#1:p#4Eoo43 Op/Oi/8owO/i/#is#the#timeO/p/#O==/#1:p#1:i#48ow43#4#is#the#time43
:o6 the only proble* i! 6here to !FueeAe in the #ttribute!. Since *o!t ele*ent! h#?e no #ttribute!, it@d be nice i' you could u!e the preceding !ynt#. 'or ele*ent! 6ithout #ttribute!. /55 pro?ide! t6o 6#y! to not#te ele*ent! 6ith #ttribute!. &he 'ir!t i! to !i*ply include the #ttribute! in the li!t i**edi#tely 'ollo6ing the !y*bol, #ltern#ting 9ey6ord !y*bol! n#*ing the #ttribute! #nd ob<ect! repre!enting the #ttribute ?#lue 'or*!. &he body o' the ele*ent !t#rt! 6ith the 'ir!t ite* in the li!t th#t@! in # po!ition to be #n #ttribute n#*e #nd i!n@t # 9ey6ord !y*bol. &hu!:
:F%L/#1html#1:p#4(oo433 Op/(ooO/p/ 89L :F%L/#1html#1:p#4(oo#4#1:i#4bar43#4#ba*433 Op/(oo#Oi/barO/i/#ba*O/p/ 89L :F%L/#1html#1:p#:st?le#4(oo4#4Eoo433 Op#st?le=C(ooC/EooO/p/ 89L :F%L/#1html#1:p#:id#4)4#:st?le#4(oo4#4Eoo433 Op#id=C)C#st?le=C(ooC/EooO/p/ 89L
/or 'ol9! 6ho pre'er # bit *ore ob?iou! deline#tion bet6een the ele*ent@! #ttribute! #nd it! body, /55 !upport! #n #ltern#ti?e !ynt#.: i' the 'ir!t ele*ent o' # li!t i! it!el' # li!t 6ith # 9ey6ord #! its 'ir!t ele*ent, then the outer li!t repre!ent! #n >&3 ele*ent 6ith th#t 9ey6ord indic#ting the t#g, 6ith the REST o' the ne!ted li!t #! the #ttribute!, #nd 6ith the REST o' the outer li!t #! the body. &hu!, you could 6rite the pre?iou! t6o e.pre!!ion! li9e thi!:
:F%L/#1html#11:p#:st?le#4(oo43#4Eoo433 Op#st?le=C(ooC/EooO/p/ 89L :F%L/#1html#11:p#:id#4)4#:st?le#4(oo43#4Eoo433 Op#id=C)C#st?le=C(ooC/EooO/p/
89L
&he 'ollo6ing 'unction te!t! 6hether # gi?en ob<ect *#tche! either o' the!e !ynt#.e!:
1de('n#cons-(orm-p#1(orm#>optional#1test#NC&e?wordp33 ##1and#1consp#(orm3 #######1or#1('ncall#test#1car#(orm33 ###########1and#1consp#1car#(orm33#1('ncall#test#1caar#(orm333333
4ou !hould p#r#*eteriAe the test 'unction bec#u!e l#ter you@ll need to te!t the !#*e t6o !ynt#.e! 6ith # !lightly di''erent predic#te on the n#*e. &o co*pletely #b!tr#ct the di''erence! bet6een the t6o !ynt#. ?#ri#nt!, you c#n de'ine # 'unction, parse-cons-(orm, th#t t#9e! # 'or* #nd p#r!e! it into three ele*ent!, the t#g, the #ttribute! pli!t, #nd the body li!t, returning the* #! *ultiple ?#lue!. &he code th#t #ctu#lly e?#lu#te! con! 'or*! 6ill u!e thi! 'unction #nd not h#?e to 6orry #bout 6hich !ynt#. 6#! u!ed.
1de('n#parse-cons-(orm#1se)p3 ##1i(#1consp#1(irst#se)p33 ####1parse-e)plicit-attrib'tes-se)p#se)p3 ####1parse-implicit-attrib'tes-se)p#se)p333 1de('n#parse-e)plicit-attrib'tes-se)p#1se)p3 ##1destr'ct'ring-bind#11tag#>rest#attrib'tes3#>bod?#bod?3#se)p ####1val'es#tag#attrib'tes#bod?333 1de('n#parse-implicit-attrib'tes-se)p#1se)p3 ##1loop#with#tag#=#1(irst#se)p3 #####(or#rest#on#1rest#se)p3#b?#NCcddr #####while#1and#1&e?wordp#1(irst#rest33#1second#rest33 #####when#1second#rest3 #######collect#1(irst#rest3#into#attrib'tes#and #######collect#1second#rest3#into#attrib'tes #####end #####(inall?#1ret'rn#1val'es#tag#attrib'tes#rest3333
:o6 th#t you h#?e the b#!ic l#ngu#ge !peci'ied, you c#n thin9 #bout ho6 you@re #ctu#lly going to i*ple*ent the l#ngu#ge proce!!or!. >o6 do you get 'ro* # !erie! o' /55 'or*! to the de!ired >&3 " %! I *entioned pre?iou!ly, you@ll be i*ple*enting t6o l#ngu#ge proce!!or! 'or /55: #n interpreter th#t 6#l9! # tree o' /55 'or*! #nd e*it! the corre!ponding >&3 directly #nd # co*piler th#t 6#l9! # tree #nd tr#n!l#te! it into Co**on i!p code th#t@ll e*it the !#*e >&3 . 7oth the interpreter #nd co*piler 6ill be built on top o' # co**on 'ound#tion o' code, 6hich pro?ide! !upport 'or thing! !uch #! e!c#ping re!er?ed ch#r#cter! #nd gener#ting nicely indented output, !o it *#9e! !en!e to !t#rt there.
#haracter !scaping
&he 'ir!t bit o' the 'ound#tion you@ll need to l#y i! the code th#t 9no6! ho6 to e!c#pe ch#r#cter! 6ith # !peci#l *e#ning in >&3 . &here #re three !uch ch#r#cter!, #nd they *u!t not #ppe#r in the te.t o' #n ele*ent or in #n #ttribute ?#lueG they #re O, /, #nd >. In ele*ent te.t or #ttribute ?#lue!, the!e ch#r#cter! *u!t be repl#ced 6ith the character reference entities >ltS, >gtG, #nd >ampS. Si*il#rly, in #ttribute ?#lue!, the Fuot#tion *#r9! u!ed to deli*it the ?#lue *u!t be e!c#ped, C 6ith >aposS #nd 4 6ith >@'otS. %ddition#lly, #ny ch#r#cter c#n be repre!ented by # nu*eric ch#r#cter re'erence entity con!i!ting o' #n #*per!#nd, 'ollo6ed by # !h#rp !ign, 'ollo6ed by the nu*eric code #! # b#!e 10 integer, #nd 'ollo6ed by # !e*icolon. &he!e nu*eric e!c#pe! #re !o*eti*e! u!ed to e*bed non-%SCII
ch#r#cter! in >&3 . &he P#c9#ge Since /55 i! # lo6-le?el libr#ry, the p#c9#ge you de?elop it in doe!n@t rely on *uch e.tern#l code--<u!t the u!u#l dependency on n#*e! 'ro* the $;%%;8-L9,T p#c9#ge #nd, #l*o!t #! u!u#l, on the n#*e! o' the *#cro-6riting *#cro! 'ro* $;%.J9JI%;8M-H,.%I$.;-+F9L9F9-,. 5n the other h#nd, the p#c9#ge need! to e.port #ll the n#*e! needed by code th#t u!e! /55. >ere@! the DEFPAC+AGE 'ro* the !ource th#t you c#n do6nlo#d 'ro* the boo9@! Web !ite:
1de(pac&age#:com.gigamon&e?s.html ##1:'se#:common-lisp#:com.gigamon&e?s.macro-'tilities3 ##1:e)port#:with-html-o'tp't ###########:in-html-st?le ###########:de(ine-html-macro ###########:html ###########:emit-html ###########:>attrib'tes33
&he 'ollo6ing 'unction #ccept! # !ingle ch#r#cter #nd return! # !tring cont#ining # ch#r#cter re'erence entity 'or th#t ch#r#cter:
1de('n#escape-char#1char3 ##1case#char ####1NY>#4>ampS43 ####1NYO#4>ltS43 ####1NY/#4>gtS43 ####1NYC#4>aposS43 ####1NY4#4>@'otS43 ####1t#1(ormat#nil#4>N7dS4#1char-code#char33333
4ou c#n u!e thi! 'unction #! the b#!i! 'or # 'unction, escape, th#t t#9e! # !tring #nd # !eFuence o' ch#r#cter! #nd return! # copy o' the 'ir!t #rgu*ent 6ith #ll occurrence! o' the ch#r#cter! in the !econd #rgu*ent repl#ced 6ith the corre!ponding ch#r#cter entity returned by escape-char.
1de('n#escape#1in#to-escape3 ##1(let#11needs-escape-p#1char3#1(ind#char#to-escape333 ####1with-o'tp't-to-string#1o't3 ######1loop#(or#start#=# #then#102#pos3 ############(or#pos#=#1position-i(#NCneeds-escape-p#in#:start#start3 ############do#1write-se@'ence#in#o't#:start#start#:end#pos3 ############when#pos#do#1write-se@'ence#1escape-char#1char#in#pos33#o't3 ############while#pos3333
4ou c#n #l!o de'ine t6o p#r#*eter!: Uelement-escapesU, 6hich cont#in! the ch#r#cter! you need to e!c#pe in nor*#l ele*ent d#t#, #nd Uattrib'te-escapesU, 6hich cont#in! the !et o' ch#r#cter! to be e!c#ped in #ttribute ?#lue!.
1de(parameter#Uelement-escapesU#4O/>43 1de(parameter#Uattrib'te-escapesU#4O/>Y4C43
:F%L/#1escape#4(oo#>#CbarC4#Uattrib'te-escapesU3 4(oo#>ampS#>aposSbar>aposS4
/in#lly, you@ll need # ?#ri#ble, UescapesU, th#t 6ill be bound to the !et o' ch#r#cter! th#t need to be e!c#ped. It@! initi#lly !et to the ?#lue o' Uelement-escapesU, but 6hen gener#ting #ttribute!, it 6ill, #! you@ll !ee, be rebound to the ?#lue o' Uattrib'te-escapesU.
1de(var#UescapesU#Uelement-escapesU3
Indenting "rinter
&o h#ndle gener#ting nicely indented output, you c#n de'ine # cl#!! indenting-printer, 6hich 6r#p! #round #n output !tre#*, #nd 'unction! th#t u!e #n in!t#nce o' th#t cl#!! to e*it !tring! to the !tre#* 6hile 9eeping tr#c9 o' 6hen it@! #t the beginning o' the line. &he cl#!! loo9! li9e thi!:
1de(class#indenting-printer#13 ##11o't#################:accessor#o't#################:initarg#:o't3 ###1beginning-o(-line-p#:accessor#beginning-o(-line-p#:init(orm#t3 ###1indentation#########:accessor#indentation#########:init(orm# 3 ###1indenting-p#########:accessor#indenting-p#########:init(orm#t333
&he *#in 'unction th#t oper#te! on indenting-printer! i! emit, 6hich t#9e! the printer #nd # !tring #nd e*it! the !tring to the printer@! output !tre#*, 9eeping tr#c9 o' 6hen it e*it! # ne6line !o it c#n re!et the beginning-o(-line-p !lot.
1de('n#emit#1ip#string3 ##1loop#(or#start#=# #then#102#pos3 #####(or#pos#=#1position#NY8ewline#string#:start#start3 #####do#1emit/no-newlines#ip#string#:start#start#:end#pos3 #####when#pos#do#1emit-newline#ip3 #####while#pos33
&o #ctu#lly e*it the !tring, it u!e! the 'unction emit/no-newlines, 6hich e*it! #ny needed indent#tion, ?i# the helper indent-i(-necessar?, #nd then 6rite! the !tring to the !tre#*. &hi! 'unction c#n #l!o be c#lled directly by other code to e*it # !tring th#t@! 9no6n not to cont#in #ny ne6line!.
1de('n#emit/no-newlines#1ip#string#>&e?#1start# 3#end3 ##1indent-i(-necessar?#ip3 ##1write-se@'ence#string#1o't#ip3#:start#start#:end#end3 ##1'nless#1*erop#1-#1or#end#1length#string33#start33 ####1set(#1beginning-o(-line-p#ip3#nil333
&he helper indent-i(-necessar? chec9! beginning-o(-line-p #nd indenting-p to deter*ine 6hether it need! to e*it indent#tion #nd, i' they@re both true, e*it! #! *#ny !p#ce! #! indic#ted by the ?#lue o' indentation. Code th#t u!e! the indenting-printer c#n control the indent#tion by *#nipul#ting the indentation #nd indenting-p !lot!. Incre*enting #nd decre*enting indentation ch#nge! the nu*ber o' le#ding !p#ce!, 6hile !etting indenting-p to NIL c#n te*por#rily turn o'' indent#tion.
1de('n#indent-i(-necessar?#1ip3 ##1when#1and#1beginning-o(-line-p#ip3#1indenting-p#ip33 ####1loop#repeat#1indentation#ip3#do#1write-char#NY,pace#1o't#ip333 ####1set(#1beginning-o(-line-p#ip3#nil333
&he l#!t t6o 'unction! in the indenting-printer %PI #re emit-newline #nd emit(reshline, 6hich #re both u!ed to e*it # ne6line ch#r#cter, !i*il#r to the 76 #nd 7> FORMAT directi?e!. &h#t i!, the only di''erence i! th#t emit-newline #l6#y! e*it! # ne6line, 6hile emit(reshline doe! !o only i' beginning-o(-line-p i! '#l!e. &hu!, *ultiple c#ll! to emit(reshline 6ithout #ny inter?ening emit! 6on@t re!ult in # bl#n9 line. &hi! i! h#ndy 6hen one piece o' code 6#nt! to gener#te !o*e output th#t !hould end 6ith # ne6line 6hile #nother piece o' code 6#nt! to gener#te !o*e output th#t !hould !t#rt on # ne6line but you don@t 6#nt # bl#n9 line bet6een the t6o bit! o' output.
1de('n#emit-newline#1ip3 ##1write-char#NY8ewline#1o't#ip33 ##1set(#1beginning-o(-line-p#ip3#t33 1de('n#emit-(reshline#1ip3 ##1'nless#1beginning-o(-line-p#ip3#1emit-newline#ip333
With tho!e preli*in#rie! out o' the 6#y, you@re re#dy to get to the gut! o' the /55 proce!!or.
While !e?er#l o' the!e 'unction! h#?e ob?iou! corre!pondence to indenting-printer 'unction!, it@! i*port#nt to under!t#nd th#t the!e generic 'unction! de'ine the #b!tr#ct oper#tion! th#t #re u!ed by the /55 l#ngu#ge proce!!or! #nd 6on@t #l6#y! be i*ple*ented in ter*! o' c#ll! to the indentingprinter 'unction!. &h#t !#id, perh#p! the e#!ie!t 6#y to under!t#nd the !e*#ntic! o' the!e #b!tr#ct oper#tion! i! to loo9 #t the concrete i*ple*ent#tion! o' the *ethod! !peci#liAed on html-prett?-printer, the cl#!! u!ed to gener#te hu*#n-re#d#ble >&3 .
:o6 you c#n i*ple*ent *ethod! !peci#liAed on html-prett?-printer on the eight generic 'unction! th#t *#9e up the b#c9end inter'#ce. &he /55 proce!!or! u!e the raw-string 'unction to e*it !tring! th#t don@t need ch#r#cter e!c#ping, either bec#u!e you #ctu#lly 6#nt to e*it nor*#lly re!er?ed ch#r#cter! or bec#u!e #ll re!er?ed ch#r#cter! h#?e #lre#dy been e!c#ped. 8!u#lly raw-string i! in?o9ed 6ith !tring! th#t don@t cont#in ne6line!, !o the de'#ult beh#?ior i! to u!e emit/no-newlines unle!! the c#ller !peci'ie! # nonNIL newlines-p #rgu*ent.
1de(method#raw-string#11pp#html-prett?-printer3#string#>optional#newlines-p3 ##1i(#newlines-p ####1emit#1printer#pp3#string3 ####1emit/no-newlines#1printer#pp3#string333
&he 'unction! newline, (reshline, indent, 'nindent, #nd toggle-indenting i*ple*ent '#irly !tr#ight'or6#rd *#nipul#tion! o' the underlying indenting-printer. &he only 6rin9le i! th#t the >&3 pretty printer gener#te! pretty output only 6hen the dyn#*ic ?#ri#ble Uprett?U i! true. When it@! NIL, you !hould gener#te co*p#ct >&3 6ith no unnece!!#ry 6hite!p#ce. So, the!e *ethod!, 6ith the e.ception o' newline, #ll chec9 Uprett?U be'ore doing #nything:5
1de(method#newline#11pp#html-prett?-printer33 ##1emit-newline#1printer#pp333 1de(method#(reshline#11pp#html-prett?-printer33 ##1when#Uprett?U#1emit-(reshline#1printer#pp3333 1de(method#indent#11pp#html-prett?-printer33 ##1when#Uprett?U# ####1inc(#1indentation#1printer#pp33#1tab-width#pp3333 1de(method#'nindent#11pp#html-prett?-printer33 ##1when#Uprett?U# ####1dec(#1indentation#1printer#pp33#1tab-width#pp3333 1de(method#toggle-indenting#11pp#html-prett?-printer33 ##1when#Uprett?U# ####1with-slots#1indenting-p3#1printer#pp3 ######1set(#indenting-p#1not#indenting-p33333
/in#lly, the 'unction! embed-val'e #nd embed-code #re u!ed only by the /55 co*piler-embed-val'e i! u!ed to gener#te code th#t@ll e*it the ?#lue o' # Co**on i!p e.pre!!ion, 6hile embed-code i! u!ed to e*bed # bit o' code to be run #nd it! re!ult di!c#rded. In the interpreter, you c#n@t *e#ning'ully e?#lu#te e*bedded i!p code, !o the *ethod! on the!e 'unction! #l6#y! !ign#l #n error.
1de(method#embed-val'e#11pp#html-prett?-printer3#val'e3 ##1error#4$anCt#embed#val'es#when##interpreting.#Kal'e:#7s4#val'e33 1de(method#embed-code#11pp#html-prett?-printer3#code3 ##1error#4$anCt#embed#code#when#interpreting.#$ode:#7s4#code33
8!ing Condition! to >#?e 4our C#9e #nd (#t It &oo %n #ltern#te #ppro#ch 6ould be to u!e EVAL to e?#lu#te i!p e.pre!!ion! in the interpreter. &he proble* 6ith thi! #ppro#ch i! th#t EVAL h#! no #cce!! to the le.ic#l en?iron*ent. &hu!, there@! no 6#y to *#9e !o*ething li9e thi! 6or9:
1let#11)#0 33#1emit-html#C1:p#)333
6hen ) i! # le.ic#l ?#ri#ble. &he !y*bol ) th#t@! p#!!ed to emit-html #t runti*e h#! no p#rticul#r connection to the le.ic#l ?#ri#ble n#*ed 6ith the !#*e !y*bol. &he i!p co*piler #rr#nge! 'or re'erence! to ) in the code to re'er to the ?#ri#ble, but #'ter the code i! co*piled, there@! no longer nece!!#rily #ny #!!oci#tion bet6een the n#*e ) #nd th#t ?#ri#ble. &hi! i! the *#in re#!on th#t 6hen you thin9 EVAL i! the !olution to your proble*, you@re prob#bly 6rong. >o6e?er, i' ) 6#! # dyn#*ic ?#ri#ble, decl#red 6ith DEFVAR or DEFPARAMETER B#nd li9ely n#*ed U)U in!te#d o' )C, EVAL could get #t it! ?#lue. &hu!, it *ight be u!e'ul to #llo6 the /55 interpreter to u!e EVAL in !o*e !itu#tion!. 7ut it@! # b#d ide# to #l6#y! u!e EVAL. 4ou c#n get the be!t o' both 6orld! by co*bining the ide# o' u!ing EVAL 6ith the condition !y!te*. /ir!t de'ine !o*e error cl#!!e! th#t you c#n !ign#l 6hen embed-val'e #nd embed-code #re c#lled in the interpreter.
1de(ine-condition#embedded-lisp-in-interpreter#1error3 ##11(orm#:initarg#:(orm#:reader#(orm333 1de(ine-condition#val'e-in-interpreter#1embedded-lisp-in-interpreter3#13 ##1:report ###1lambda#1c#s3# #####1(ormat#s#4$anCt#embed#val'es#when#interpreting.#Kal'e:#7s4#1(orm#c33333 1de(ine-condition#code-in-interpreter#1embedded-lisp-in-interpreter3#13 ##1:report ###1lambda#1c#s3# #####1(ormat#s#4$anCt#embed#code#when#interpreting.#$ode:#7s4#1(orm#c33333
:o6 you c#n i*ple*ent embed-val'e #nd embed-code to !ign#l tho!e error! and pro?ide # re!t#rt th#t@ll e?#lu#te the 'or* 6ith EVAL.
1de(method#embed-val'e#11pp#html-prett?-printer3#val'e3 ##1restart-case#1error#Cval'e-in-interpreter#:(orm#val'e3 ####1eval'ate#13 ######:report#1lambda#1s3#1(ormat#s#4-KIL#7s#in#n'll#le)ical#environment.4#val'e33 ######1raw-string#pp#1escape#1princ-to-string#1eval#val'e33#UescapesU3#t3333
#nd you@ll get dropped into the debugger 6ith thi! *e!!#ge:
$anCt#embed#val'es#when#interpreting.#Kal'e:#U[U ###D$ondition#o(#t?pe#KIL+--98-98F-.T.-F-.G .estarts: ## :#D-KIL+IF-G#-KIL#U[U#in#n'll#le)ical#environment. ##0:#DIL;.FG#Ibort#handling#,L9%-#re@'est. ##!:#DIL;.FG#Ibort#entirel?#(rom#this#process.
I' you in?o9e the eval'ate re!t#rt, embed-val'e 6ill EVAL U)U, get the ?#lue 0 , #nd gener#te thi! >&3 :
Op/0 O/p/
&hen, #! # con?enience, you c#n pro?ide re!t#rt 'unction!--'unction! th#t in?o9e the eval'ate re!t#rt--in cert#in !itu#tion!. &he eval'ate re!t#rt 'unction uncondition#lly in?o9e! the re!t#rt, 6hile eval-d?namic-variables #nd eval-code in?o9e it only i' the 'or* in the condition i! # dyn#*ic ?#ri#ble or potenti#l code.
1de('n#eval'ate#1>optional#condition3 ##1declare#1ignore#condition33 ##1invo&e-restart#Ceval'ate33 1de('n#eval-d?namic-variables#1>optional#condition3 ##1when#1and#1s?mbolp#1(orm#condition33#1bo'ndp#1(orm#condition333 ####1eval'ate333 1de('n#eval-code#1>optional#condition3 ##1when#1consp#1(orm#condition33 ####1eval'ate333
:o6 you c#n u!e HANDLER-BIND to !et up # h#ndler to #uto*#tic#lly in?o9e the eval'ate re!t#rt 'or you.
:F%L/#1handler-bind#11val'e-in-interpreter#NCeval'ate33#1emit-html#C1:p#U)U333 Op/0 O/p/ F
/in#lly, you c#n de'ine # *#cro to pro?ide # nicer !ynt#. 'or binding h#ndler! 'or the t6o 9ind! o' error!.
1de(macro#with-d?namic-eval'ation#11>&e?#val'es#code3#>bod?#bod?3 ##B1handler-bind#1
thi! 'unction *ight e.ecute thi! !eFuence o' c#ll! on the proce!!or:
1(reshline#processor3 1raw-string#processor#4Op4#nil3 1raw-string#processor#4/4#nil3 1raw-string#processor#4Eoo4#nil3 1raw-string#processor#4O/p/4#nil3 1(reshline#processor3
/or no6 you c#n de'ine # !i*ple 'unction th#t <u!t chec9! 6hether # 'or* i!, in '#ct, # leg#l /55 'or* #nd, i' it i!, h#nd! it o'' to the 'unction process-se)p-html 'or proce!!ing. In the ne.t ch#pter, you@ll #dd !o*e bell! #nd 6hi!tle! to thi! 'unction to #llo6 it to h#ndle *#cro! #nd !peci#l oper#tor!. 7ut 'or no6 it loo9! li9e thi!:
1de('n#process#1processor#(orm3 ##1i(#1se)p-html-p#(orm3 ####1process-se)p-html#processor#(orm3 ####1error#4%al(ormed#E;;#(orm:#7s4#(orm333
&he 'unction se)p-html-p deter*ine! 6hether the gi?en ob<ect i! # leg#l /55 e.pre!!ion, either # !el'-e?#lu#ting 'or* or # properly 'or*#tted con!.
1de('n#se)p-html-p#1(orm3 ##1or#1sel(-eval'ating-p#(orm3#1cons-(orm-p#(orm333
Sel'-e?#lu#ting 'or*! #re e#!ily h#ndled: <u!t con?ert to # !tring 6ith PRINC-TO-STRING #nd e!c#pe the ch#r#cter! in the ?#ri#ble UescapesU, 6hich, #! you@ll rec#ll, i! initi#lly bound to the ?#lue o' Uelement-escapesU. Con! 'or*! you p#!! o'' to process-cons-se)p-html.
1de('n#process-se)p-html#1processor#(orm3 ##1i(#1sel(-eval'ating-p#(orm3 ####1raw-string#processor#1escape#1princ-to-string#(orm3#UescapesU3#t3 ####1process-cons-se)p-html#processor#(orm333
&he 'unction process-cons-se)p-html i! then re!pon!ible 'or e*itting the opening t#g, #ny #ttribute!, the body, #nd the clo!ing t#g. &he *#in co*plic#tion here i! th#t to gener#te pretty >&3 , you need to e*it 're!h line! #nd #d<u!t the indent#tion #ccording to the type o' the ele*ent being
e*itted. 4ou c#n c#tegoriAe #ll the ele*ent! de'ined in >&3 into one o' three c#tegorie!: bloc9, p#r#gr#ph, #nd inline. 7loc9 ele*ent!--!uch #! bod? #nd 'l--#re e*itted 6ith 're!h line! be'ore #nd #'ter both their opening #nd clo!ing t#g! #nd 6ith their content! indented one le?el. P#r#gr#ph ele*ent!--!uch #! p, li, #nd bloc&@'ote--#re e*itted 6ith # 're!h line be'ore the opening t#g #nd #'ter the clo!ing t#g. Inline ele*ent! #re !i*ply e*itted in line. &he 'ollo6ing three p#r#*eter! li!t the ele*ent! o' e#ch type:
1de(parameter#Ubloc&-elementsU ##C1:bod?#:colgro'p#:dl#:(ieldset#:(orm#:head#:html#:map#:noscript#:object ####:ol#:optgro'p#:pre#:script#:select#:st?le#:table#:tbod?#:t(oot#:thead ####:tr#:'l33 1de(parameter#Uparagraph-elementsU ##C1:area#:base#:bloc&@'ote#:br#:b'tton#:caption#:col#:dd#:div#:dt#:h0 ####:h!#:h3#:h4#:h"#:h6#:hr#:inp't#:li#:lin&#:meta#:option#:p#:param ####:td#:te)tarea#:th#:title33 1de(parameter#Uinline-elementsU ##C1:a#:abbr#:acron?m#:address#:b#:bdo#:big#:cite#:code#:del#:d(n#:em ####:i#:img#:ins#:&bd#:label#:legend#:@#:samp#:small#:span#:strong#:s'b ####:s'p#:tt#:var33
&he 'unction! bloc&-element-p #nd paragraph-element-p te!t 6hether # gi?en t#g i! # *e*ber o' the corre!ponding li!t.0
1de('n#bloc&-element-p#1tag3#1(ind#tag#Ubloc&-elementsU33 1de('n#paragraph-element-p#1tag3#1(ind#tag#Uparagraph-elementsU33
&6o other c#tegoriA#tion! 6ith their o6n predic#te! #re the ele*ent! th#t #re #l6#y! e*pty, !uch #! br# #nd hr, #nd the three ele*ent!, pre, st?le, #nd script, in 6hich 6hite!p#ce i! !uppo!ed to be pre!er?ed. &he 'or*er #re h#ndled !peci#lly 6hen gener#ting regul#r >&3 Bin other 6ord!, not N>&3 C !ince they@re not !uppo!ed to h#?e # clo!ing t#g. %nd 6hen e*itting the three t#g! in 6hich 6hite!p#ce i! pre!er?ed, you c#n te*por#rily turn o'' indent#tion !o the pretty printer doe!n@t #dd #ny !p#ce! th#t #ren@t p#rt o' the ele*ent@! #ctu#l content!.
1de(parameter#Uempt?-elementsU ##C1:area#:base#:br#:col#:hr#:img#:inp't#:lin&#:meta#:param33 1de(parameter#Upreserve-whitespace-elementsU#C1:pre#:script#:st?le33 1de('n#empt?-element-p#1tag3#1(ind#tag#Uempt?-elementsU33 1de('n#preserve-whitespace-p#1tag3#1(ind#tag#Upreserve-whitespace-elementsU33
&he l#!t piece o' in'or*#tion you need 6hen gener#ting >&3 i! 6hether you@re gener#ting N>&3 !ince th#t #''ect! ho6 you e*it e*pty ele*ent!.
1de(parameter#U)htmlU#nil3
With #ll th#t in'or*#tion, you@re re#dy to proce!! # con! /55 'or*. 4ou u!e parse-cons-(orm to p#r!e the li!t into three p#rt!, the t#g !y*bol, # po!!ibly e*pty pli!t o' #ttribute 9ey;?#lue p#ir!, #nd # po!!ibly e*pty li!t o' body 'or*!. 4ou then e*it the opening t#g, the body, #nd the clo!ing t#g 6ith the helper 'unction! emit-open-tag, emit-element-bod?, #nd emit-close-tag.
In emit-open-tag you h#?e to c#ll (reshline 6hen #ppropri#te #nd then e*it the #ttribute! 6ith emit-attrib'tes. 4ou need to p#!! the ele*ent@! body to emit-open-tag !o 6hen it@! e*itting N>&3 , it 9no6! 6hether to 'ini!h the t#g 6ith // or /.
1de('n#emit-open-tag#1processor#tag#bod?-p#attrib'tes3 ##1when#1or#1paragraph-element-p#tag3#1bloc&-element-p#tag33 ####1(reshline#processor33 ##1raw-string#processor#1(ormat#nil#4O717a734#tag33 ##1emit-attrib'tes#processor#attrib'tes3 ##1raw-string#processor#1i(#1and#U)htmlU#1not#bod?-p33#4//4#4/4333
In emit-attrib'tes the #ttribute n#*e! #ren@t e?#lu#ted !ince they *u!t be 9ey6ord !y*bol!, but you !hould in?o9e the top-le?el process 'unction to e?#lu#te the #ttribute ?#lue!, binding UescapesU to Uattrib'te-escapesU. %! # con?enience 'or !peci'ying boole#n #ttribute!, 6ho!e ?#lue !hould be the n#*e o' the #ttribute, i' the ?#lue i! T--not <u!t #ny true ?#lue but #ctu#lly T--then you repl#ce the ?#lue 6ith the n#*e o' the #ttribute.2
1de('n#emit-attrib'tes#1processor#attrib'tes3 ##1loop#(or#1&#v3#on#attrib'tes#b?#NCcddr#do #######1raw-string#processor#1(ormat#nil#4#717a73=C4#&33 #######1let#11UescapesU#Uattrib'te-escapesU33 #########1process#processor#1i(#1e@l#v#t3#1string-downcase#&3#v333 #######1raw-string#processor#4C4333
(*itting the ele*ent@! body i! !i*il#r to e*itting the #ttribute ?#lue!: you c#n loop through the body c#lling process to e?#lu#te e#ch 'or*. &he re!t o' the code i! dedic#ted to e*itting 're!h line! #nd #d<u!ting the indent#tion #! #ppropri#te 'or the type o' ele*ent.
1de('n#emit-element-bod?#1processor#tag#bod?3 ##1when#1bloc&-element-p#tag3 ####1(reshline#processor3 ####1indent#processor33 ##1when#1preserve-whitespace-p#tag3#1toggle-indenting#processor33 ##1dolist#1item#bod?3##1process#processor#item33 ##1when#1preserve-whitespace-p#tag3#1toggle-indenting#processor33 ##1when#1bloc&-element-p#tag3 ####1'nindent#processor3 ####1(reshline#processor333
/in#lly, emit-close-tag, #! you@d prob#bly e.pect, e*it! the clo!ing t#g Bunle!! no clo!ing t#g i! nece!!#ry, !uch #! 6hen the body i! e*pty #nd you@re either e*itting N>&3 or the ele*ent i! one o' the !peci#l e*pty ele*ent!C. $eg#rdle!! o' 6hether you #ctu#lly e*it # clo!e t#g, you need to e*it # 'in#l 're!h line 'or bloc9 #nd p#r#gr#ph ele*ent!.
1de('n#emit-close-tag#1processor#tag#bod?-p3 ##1'nless#1and#1or#U)htmlU#1empt?-element-p#tag33#1not#bod?-p33 ####1raw-string#processor#1(ormat#nil#4O/717a73/4#tag333 ##1when#1or#1paragraph-element-p#tag3#1bloc&-element-p#tag33
####1(reshline#processor333
&he 'unction process i! the b#!ic /55 interpreter. &o *#9e it # bit e#!ier to u!e, you c#n de'ine # 'unction, emit-html, th#t in?o9e! process, p#!!ing it #n html-prett?-printer #nd # 'or* to e?#lu#te. 4ou c#n de'ine #nd u!e # helper 'unction, get-prett?-printer, to get the pretty printer, 6hich return! the current ?#lue o' Uhtml-prett?-printerU i' it@! boundG other6i!e, it *#9e! # ne6 in!t#nce o' html-prett?-printer 6ith Uhtml-o'tp'tU #! it! output !tre#*.
1de('n#emit-html#1se)p3#1process#1get-prett?-printer3#se)p33 1de('n#get-prett?-printer#13 ##1or#Uhtml-prett?-printerU ######1ma&e-instance# #######Chtml-prett?-printer #######:printer#1ma&e-instance#Cindenting-printer#:o't#Uhtml-o'tp'tU3333
With thi! 'unction, you c#n e*it >&3 to Uhtml-o'tp'tU. $#ther th#n e.po!e the ?#ri#ble Uhtml-o'tp'tU #! p#rt o' /55@! public %PI, you !hould de'ine # *#cro, with-html-o'tp't, th#t t#9e! c#re o' binding the !tre#* 'or you. It #l!o let! you !peci'y 6hether you 6#nt pretty >&3 output, de'#ulting to the ?#lue o' the ?#ri#ble Uprett?U.
1de(macro#with-html-o'tp't#11stream#>&e?#1prett?#Uprett?U33#>bod?#bod?3 ##B1letU#11Uhtml-o'tp'tU#5stream3 ##########1Uprett?U#5prett?33 ####5Pbod?33
So, i' you 6#nted to u!e emit-html to gener#te >&3 to # 'ile, you could 6rite the 'ollo6ing:
1with-open-(ile#1o't#4(oo.html4#:direction#o'tp't3 ##1with-html-o'tp't#1o't#:prett?#t3 ####1emit-html#Usome-(oo-e)pressionU333
What6s :e)t?
In the ne.t ch#pter, you@ll loo9 #t ho6 to i*ple*ent # *#cro th#t co*pile! /55 e.pre!!ion! into Co**on i!p !o you c#n e*bed >&3 gener#tion code directly into your i!p progr#*!. 4ou@ll #l!o e.tend the /55 l#ngu#ge to *#9e it # bit *ore e.pre!!i?e by #dding it! o6n 'l#?or o' !peci#l oper#tor! #nd *#cro!.
1In
'#ct, it@! prob#bly too e.pre!!i?e !ince it c#n #l!o gener#te #ll !ort! o' output th#t@! not e?en ?#guely leg#l >&3 . 5' cour!e, th#t *ight be # 'e#ture i' you need to gener#te >&3 th#t@! not !trictly correct to co*pen!#te 'or buggy Web bro6!er!. %l!o, it@! co**on 'or l#ngu#ge proce!!or! to #ccept progr#*! th#t #re !ynt#ctic#lly correct #nd other6i!e 6ell 'or*ed th#t@ll nonethele!! pro?o9e unde'ined beh#?ior 6hen run.
2Well, 3In
#l*o!t e?ery t#g. Cert#in t#g! !uch #! 9%J #nd L. don@t. 4ou@ll de#l 6ith tho!e in the !ection H&he 7#!ic (?#lu#tion $ule.H the !trict l#ngu#ge o' the Co**on i!p !t#nd#rd, 9ey6ord !y*bol! #ren@t self)evaluating, though they do, in '#ct, e?#lu#te to the*!el?e!. See !ection 3.1.2.1.3 o' the l#ngu#ge !t#nd#rd or >yperSpec 'or # brie' di!cu!!ion.
-&he
reFuire*ent to u!e ob<ect! th#t the i!p re#der 9no6! ho6 to re#d i!n@t # h#rd-#nd-'#!t one. Since the i!p re#der i! it!el' cu!to*iA#ble, you could #l!o de'ine # ne6 re#der-le?el !ynt#. 'or # ne6 9ind o' ob<ect. 7ut th#t tend! to be *ore trouble th#n it@! 6orth.
5%nother,
*ore purely ob<ect-oriented, #ppro#ch 6ould be to de'ine t6o cl#!!e!, perh#p! htmlprett?-printer #nd html-raw-printer, #nd then de'ine no-op *ethod! !peci#liAed on html-raw-printer 'or the *ethod! th#t !hould do !tu'' only 6hen Uprett?U i! true. >o6e?er, in thi! c#!e, #'ter de'ining #ll the no-op *ethod!, you@d end up 6ith *ore code, #nd then you@d h#?e the h#!!le o' *#9ing !ure you cre#ted #n in!t#nce o' the right cl#!! #t the right ti*e. 7ut in gener#l, u!ing poly*orphi!* to repl#ce condition#l! i! # good !tr#tegy.
04ou
don@t need # predic#te 'or Uinline-elementsU !ince you only e?er te!t 'or bloc9 #nd p#r#gr#ph ele*ent!. I include the p#r#*eter here 'or co*pletene!!.
2While
N>&3 reFuire! boole#n #ttribute! to be not#ted 6ith their n#*e #! the ?#lue to indic#te # true ?#lue, in >&3 it@! #l!o leg#l to !i*ply include the n#*e o' the #ttribute 6ith no ?#lue, 'or e.#*ple, 1o !"o# ('%'<!'/2 r#ther th#n 1o !"o# ('%'<!'/=@('%'<!'/@2. %ll >&3 -.0co*p#tible bro6!er! !hould under!t#nd both 'or*!, but !o*e buggy bro6!er! under!t#nd only the no?#lue 'or* 'or cert#in #ttribute!. I' you need to gener#te >&3 'or !uch bro6!er!, you@ll need to h#c9 emit-attrib'tes to e*it tho!e #ttribute! # bit di''erently.
The #o$pi%er
&he b#!ic #rchitecture o' the co*piler con!i!t! o' three l#yer!. /ir!t you@ll i*ple*ent # cl#!! htmlcompiler th#t h#! one !lot th#t hold! #n #d<u!t#ble ?ector th#t@! u!ed to #ccu*ul#te ops repre!enting the c#ll! *#de to the generic 'unction! in the b#c9end inter'#ce during the e.ecution o' process. 4ou@ll then i*ple*ent *ethod! on the generic 'unction! in the b#c9end inter'#ce th#t 6ill !tore the !eFuence o' #ction! in the ?ector. (#ch op i! repre!ented by # li!t con!i!ting o' # 9ey6ord n#*ing the oper#tion #nd the #rgu*ent! p#!!ed to the 'unction th#t gener#ted the op. &he 'unction se)p-/ops i*ple*ent! the 'ir!t ph#!e o' the co*piler, co*piling # li!t o' /55 'or*! by c#lling process on e#ch 'or* 6ith #n in!t#nce o' html-compiler. &hi! ?ector o' op! !tored by the co*piler i! then p#!!ed to # 'unction th#t opti*iAe! it, *erging con!ecuti?e raw-string op! into # !ingle op th#t e*it! the co*bined !tring in one go. &he opti*iA#tion 'unction c#n #l!o, option#lly, !trip out op! th#t #re needed only 'or pretty printing, 6hich i! *o!tly i*port#nt bec#u!e it #llo6! you to *erge *ore raw-string op!.
/in#lly, the opti*iAed op! ?ector i! p#!!ed to # third 'unction, generate-code, th#t return! # li!t o' Co**on i!p e.pre!!ion! th#t 6ill #ctu#lly output the >&3 . When Uprett?U i! true, generate-code gener#te! code th#t u!e! the *ethod! !peci#liAed on html-prett?-printer to output pretty >&3 . When Uprett?U i! NIL, it gener#te! code th#t 6rite! directly to the !tre#* Uhtml-o'tp'tU. &he *#cro html #ctu#lly gener#te! # body th#t cont#in! t6o e.p#n!ion!, one gener#ted 6ith Uprett?U bound to T #nd one 6ith Uprett?U bound to NIL. Which e.p#n!ion i! u!ed i! deter*ined by the runti*e ?#lue o' Uprett?U. &hu!, e?ery 'unction th#t cont#in! # c#ll to html 6ill cont#in code to gener#te both pretty #nd co*p#ct output. &he other !igni'ic#nt di''erence bet6een the co*piler #nd the interpreter i! th#t the co*piler c#n e*bed i!p 'or*! in the code it gener#te!. &o t#9e #d?#nt#ge o' th#t, you need to *odi'y the process 'unction !o it c#ll! the embed-code #nd embed-val'e 'unction! 6hen #!9ed to proce!! #n e.pre!!ion th#t@! not # /55 'or*. Since #ll !el'-e?#lu#ting ob<ect! #re ?#lid /55 'or*!, the only 'or*! th#t 6on@t be p#!!ed to process-se)p-html #re li!t! th#t don@t *#tch the !ynt#. 'or /55 con! 'or*! #nd non-9ey6ord !y*bol!, the only #to*! th#t #ren@t !el'-e?#lu#ting. 4ou c#n #!!u*e th#t #ny non-/55 con! i! code to be run inline #nd #ll !y*bol! #re ?#ri#ble! 6ho!e ?#lue you !hould e*bed.
1de('n#process#1processor#(orm3 ##1cond ####11se)p-html-p#(orm3#1process-se)p-html#processor#(orm33 ####11consp#(orm3#######1embed-code#processor#(orm33 ####1t##################1embed-val'e#processor#(orm3333
:o6 let@! loo9 #t the co*piler code. /ir!t you !hould de'ine t6o 'unction! th#t !lightly #b!tr#ct the ?ector you@ll u!e to !#?e op! in the 'ir!t t6o ph#!e! o' co*pil#tion.
1de('n#ma&e-op-b'((er#13#1ma&e-arra?#0 #:adj'stable#t#:(ill-pointer# 33 1de('n#p'sh-op#1op#ops-b'((er3#1vector-p'sh-e)tend#op#ops-b'((er33
:e.t you c#n de'ine the html-compiler cl#!! #nd the *ethod! !peci#liAed on it to i*ple*ent the b#c9end inter'#ce.
1de(class#html-compiler#13 ##11ops#:accessor#ops#:init(orm#1ma&e-op-b'((er3333 1de(method#raw-string#11compiler#html-compiler3#string#>optional#newlines-p3 ##1p'sh-op#B1:raw-string#5string#5newlines-p3#1ops#compiler333 1de(method#newline#11compiler#html-compiler33 ##1p'sh-op#C1:newline3#1ops#compiler333 1de(method#(reshline#11compiler#html-compiler33 ##1p'sh-op#C1:(reshline3#1ops#compiler333 1de(method#indent#11compiler#html-compiler33 ##1p'sh-op#B1:indent3#1ops#compiler333 1de(method#'nindent#11compiler#html-compiler33 ##1p'sh-op#B1:'nindent3#1ops#compiler333 1de(method#toggle-indenting#11compiler#html-compiler33 ##1p'sh-op#B1:toggle-indenting3#1ops#compiler333
With tho!e *ethod! de'ined, you c#n i*ple*ent the 'ir!t ph#!e o' the co*piler, se)p-/ops.
1de('n#se)p-/ops#1bod?3 ##1loop#with#compiler#=#1ma&e-instance#Chtml-compiler3 #####(or#(orm#in#bod?#do#1process#compiler#(orm3 #####(inall?#1ret'rn#1ops#compiler3333
+uring thi! ph#!e you don@t need to 6orry #bout the ?#lue o' Uprett?U: <u!t record #ll the 'unction! c#lled by process. >ere@! 6h#t se)p-/ops *#9e! o' # !i*ple /55 'or*:
:F%L/#1se)p-/ops#C11:p#4Eoo4333 N11:E.-,:L98-3#1:.IW-,F.98J#4Op4#89L3#1:.IW-,F.98J#4/4#89L3 ##1:.IW-,F.98J#4Eoo4#F3#1:.IW-,F.98J#4O/p/4#89L3#1:E.-,:L98-33
&he ne.t ph#!e, optimi*e-static-o'tp't, t#9e! # ?ector o' op! #nd return! # ne6 ?ector cont#ining the opti*iAed ?er!ion. &he #lgorith* i! !i*ple--'or e#ch :raw-string op, it 6rite! the !tring to # te*por#ry !tring bu''er. &hu!, con!ecuti?e :raw-string op! 6ill build up # !ingle !tring cont#ining the conc#ten#tion o' the !tring! th#t need to be e*itted. Whene?er you encounter #n op other th#n # :raw-string op, you con?ert the built-up !tring into # !eFuence o' #ltern#ting :rawstring #nd :newline op! 6ith the helper 'unction compile-b'((er #nd then #dd the ne.t op. &hi! 'unction i! #l!o 6here you !trip out the pretty printing op! i' Uprett?U i! NIL.
1de('n#optimi*e-static-o'tp't#1ops3 ##1let#11new-ops#1ma&e-op-b'((er333 ####1with-o'tp't-to-string#1b'(3 ######1(let#11add-op#1op3# ###############1compile-b'((er#b'(#new-ops3 ###############1p'sh-op#op#new-ops333 ########1loop#(or#op#across#ops#do #############1ecase#1(irst#op3 ###############1:raw-string#1write-se@'ence#1second#op3#b'(33 ###############11:newline#:embed-val'e#:embed-code3#1add-op#op33 ###############11:indent#:'nindent#:(reshline#:toggle-indenting3 ################1when#Uprett?U#1add-op#op33333 ########1compile-b'((er#b'(#new-ops333 ####new-ops33 1de('n#compile-b'((er#1b'(#ops3 ##1loop#with#str#=#1get-o'tp't-stream-string#b'(3 #####(or#start#=# #then#102#pos3 #####(or#pos#=#1position#NY8ewline#str#:start#start3 #####when#1O#start#1length#str33 #####do#1p'sh-op#B1:raw-string#51s'bse@#str#start#pos3#nil3#ops3 #####when#pos#do#1p'sh-op#C1:newline3#ops3 #####while#pos33
&he l#!t !tep i! to tr#n!l#te the op! into the corre!ponding Co**on i!p code. &hi! ph#!e #l!o p#y! #ttention to the ?#lue o' Uprett?U. When Uprett?U i! true, it gener#te! code th#t in?o9e! the b#c9end generic 'unction! on Uhtml-prett?-printerU, 6hich 6ill be bound to #n in!t#nce o' html-prett?-printer. When Uprett?U i! NIL, it gener#te! code th#t 6rite! directly to Uhtml-o'tp'tU, the !tre#* to 6hich the pretty printer 6ould !end it! output. &he #ctu#l 'unction, generate-code, i! tri?i#l.
1de('n#generate-code#1ops3 ##1loop#(or#op#across#ops#collect#1appl?#NCop-/code#op333
%ll the 6or9 i! done by *ethod! on the generic 'unction op-/code !peci#liAing the op #rgu*ent 6ith #n EQL !peci#liAer on the n#*e o' the op.
1de(generic#op-/code#1op#>rest#operands33 1de(method#op-/code#11op#1e@l#:raw-string33#>rest#operands3 ##1destr'ct'ring-bind#1string#chec&-(or-newlines3#operands ####1i(#Uprett?U ######B1raw-string#Uhtml-prett?-printerU#5string#5chec&-(or-newlines3 ######B1write-se@'ence#5string#Uhtml-o'tp'tU3333 1de(method#op-/code#11op#1e@l#:newline33#>rest#operands3 ##1i(#Uprett?U ####B1newline#Uhtml-prett?-printerU3 ####B1write-char#NY8ewline#Uhtml-o'tp'tU333#### 1de(method#op-/code#11op#1e@l#:(reshline33#>rest#operands3 ##1i(#Uprett?U ####B1(reshline#Uhtml-prett?-printerU3 ####1error#4Lad#op#when#not#prett?-printing:#7a4#op333 1de(method#op-/code#11op#1e@l#:indent33#>rest#operands3 ##1i(#Uprett?U ####B1indent#Uhtml-prett?-printerU3 ####1error#4Lad#op#when#not#prett?-printing:#7a4#op333 1de(method#op-/code#11op#1e@l#:'nindent33#>rest#operands3 ##1i(#Uprett?U ####B1'nindent#Uhtml-prett?-printerU3 ####1error#4Lad#op#when#not#prett?-printing:#7a4#op333 1de(method#op-/code#11op#1e@l#:toggle-indenting33#>rest#operands3 ##1i(#Uprett?U ####B1toggle-indenting#Uhtml-prett?-printerU3 ####1error#4Lad#op#when#not#prett?-printing:#7a4#op333
&he t6o *o!t intere!ting op-/code *ethod! #re the one! th#t gener#te code 'or the :embedval'e #nd :embed-code op!. In the :embed-val'e *ethod, you c#n gener#te !lightly di''erent code depending on the ?#lue o' the escapes oper#nd !ince i' escapes i! NIL, you don@t need to gener#te # c#ll to escape. %nd 6hen both Uprett?U #nd escapes #re NIL, you c#n gener#te code th#t u!e! PRINC to e*it the ?#lue directly to the !tre#*.
1de(method#op-/code#11op#1e@l#:embed-val'e33#>rest#operands3 ##1destr'ct'ring-bind#1val'e#escapes3#operands ####1i(#Uprett?U ######1i(#escapes
When th#t code repl#ce! the c#ll to html in the conte.t o' the LET, you get the 'ollo6ing:
1let#11)#0 33 ##1progn ####1write-se@'ence#4Op/4#Uhtml-o'tp'tU3 ####1write-se@'ence#1escape#1princ-to-string#)3#4O/>43#Uhtml-o'tp'tU3 ####1write-se@'ence#4O/p/4#Uhtml-o'tp'tU333
#nd the re'erence to ) in the gener#ted code turn! into # re'erence to the le.ic#l ?#ri#ble 'ro* the LET !urrounding the html 'or*. &he :embed-code *ethod, on the other h#nd, i! intere!ting bec#u!e it@! !o tri?i#l. 7ec#u!e process p#!!ed the 'or* to embed-code, 6hich !t#!hed it in the :embed-code op, #ll you h#?e to do i! pull it out #nd return it.
1de(method#op-/code#11op#1e@l#:embed-code33#>rest#operands3 ##1(irst#operands33
&he outer c#ll to html e.p#nd! into code th#t doe! !o*ething li9e thi!:
1progn ##1write-se@'ence#4O'l/4#Uhtml-o'tp'tU3 ##1dolist#1)#C1(oo#bar#ba*33#1html#1:li#)333 ##1write-se@'ence#4O/'l/4#Uhtml-o'tp'tU3333
&hen i' you e.p#nd the c#ll to html in the body o' the DOLIST, you@ll get !o*ething li9e thi!:
1progn
7ut th#t doe!n@t 6or9 bec#u!e the code i! run #nd it! ?#lue di!c#rded.
:F%L/#1html#1:p#1random#0 333 Op/O/p/ 89L
In the l#ngu#ge, #! you@?e i*ple*ented it !o '#r, you could 6or9 #round thi! li*it#tion by co*puting the ?#lue out!ide the c#ll to html #nd then e*bedding it ?i# # ?#ri#ble.
:F%L/#1let#11)#1random#0 333#1html#1:p#)333 Op/0O/p/ 89L
7ut th#t@! !ort o' #nnoying, p#rticul#rly 6hen you con!ider th#t i' you could #rr#nge 'or the 'or* 1random#0 3 to be p#!!ed to embed-val'e in!te#d o' embed-code, it@d do e.#ctly 6h#t you 6#nt. So, you c#n de'ine # !peci#l oper#tor, :print, th#t@! proce!!ed by the /55 l#ngu#ge proce!!or #ccording to # di''erent rule th#n # nor*#l /55 e.pre!!ion. :#*ely, in!te#d o' gener#ting # Oprint/# ele*ent, it p#!!e! the 'or* in it! body to embed-val'e. &hu!, you c#n gener#te # p#r#gr#ph cont#ining # r#ndo* nu*ber li9e thi!:
:F%L/#1html#1:p#1:print#1random#0 3333 Op/9O/p/
89L
5b?iou!ly, thi! !peci#l oper#tor i! u!e'ul only in co*piled /55 code !ince embed-val'e doe!n@t 6or9 in the interpreter. %nother !peci#l oper#tor th#t c#n be u!ed in both interpreted #nd co*piled /55 code i! :(ormat, 6hich let! you gener#te output u!ing the FORMAT 'unction. &he #rgu*ent! to the :(ormat !peci#l oper#tor #re # !tring u!ed #! # 'or*#t control !tring #nd then #ny #rgu*ent! to be interpol#ted. When #ll the #rgu*ent! to :(ormat #re !el'-e?#lu#ting ob<ect!, # !tring i! gener#ted by p#!!ing the* to FORMAT, #nd th#t !tring i! then e*itted li9e #ny other !tring. &hi! #llo6! !uch :(ormat 'or*! to be u!ed in /55 p#!!ed to emit-html. In co*piled /55, the #rgu*ent! to :(ormat c#n be #ny i!p e.pre!!ion!. 5ther !peci#l oper#tor! pro?ide control o?er 6h#t ch#r#cter! #re #uto*#tic#lly e!c#ped #nd to e.plicitly e*it ne6line ch#r#cter!: the :noescape !peci#l oper#tor c#u!e! #ll the 'or*! in it! body to be e?#lu#ted #! regul#r /55 'or*! but 6ith UescapesU bound to NIL, 6hile :attrib'te e?#lu#te! the 'or*! in it! body 6ith UescapesU bound to Uattrib'te-escapesU. %nd :newline i! tr#n!l#ted into code to e*it #n e.plicit ne6line. So, ho6 do you de'ine !peci#l oper#tor!" &here #re t6o #!pect! to proce!!ing !peci#l oper#tor!: ho6 doe! the l#ngu#ge proce!!or recogniAe 'or*! th#t u!e !peci#l oper#tor!, #nd ho6 doe! it 9no6 6h#t code to run to proce!! e#ch !peci#l oper#tor" 4ou could h#c9 process-se)p-html to recogniAe e#ch !peci#l oper#tor #nd h#ndle it in the #ppropri#te *#nner--!peci#l oper#tor! #re, logic#lly, p#rt o' the i*ple*ent#tion o' the l#ngu#ge, #nd there #ren@t going to be th#t *#ny o' the*. >o6e?er, it@d be nice to h#?e # !lightly *ore *odul#r 6#y to #dd ne6 !peci#l oper#tor!--not bec#u!e u!er! o' /55 6ill be #ble to but <u!t 'or your o6n !#nity. +e'ine # special form #! #ny li!t 6ho!e CAR i! # !y*bol th#t@! the n#*e o' # !peci#l oper#tor. 4ou c#n *#r9 the n#*e! o' !peci#l oper#tor! by #dding # non-NIL ?#lue to the !y*bol@! property li!t under the 9ey html-special-operator. So, you c#n de'ine # 'unction th#t te!t! 6hether # gi?en 'or* i! # !peci#l 'or* li9e thi!:
1de('n#special-(orm-p#1(orm3 ##1and#1consp#(orm3#1s?mbolp#1car#(orm33#1get#1car#(orm3#Chtml-special-operator333
&he code th#t i*ple*ent! e#ch !peci#l oper#tor i! re!pon!ible 'or t#9ing #p#rt the re!t o' the li!t ho6e?er it !ee! 'it #nd doing 6h#te?er the !e*#ntic! o' the !peci#l oper#tor reFuire. %!!u*ing you@ll #l!o de'ine # 'unction process-special-(orm, 6hich 6ill t#9e the l#ngu#ge proce!!or #nd # !peci#l 'or* #nd run the #ppropri#te code to gener#te # !eFuence o' c#ll! on the proce!!or ob<ect, you c#n #ug*ent the top-le?el process 'unction to h#ndle !peci#l 'or*! li9e thi!:
1de('n#process#1processor#(orm3 ##1cond ####11special-(orm-p#(orm3#1process-special-(orm#processor#(orm33 ####11se)p-html-p#(orm3####1process-se)p-html#processor#(orm33 ####11consp#(orm3##########1embed-code#processor#(orm33 ####1t#####################1embed-val'e#processor#(orm3333
4ou *u!t #dd the special-(orm-p cl#u!e 'ir!t bec#u!e !peci#l 'or*! c#n loo9, !ynt#ctic#lly, li9e regul#r /55 e.pre!!ion! <u!t the 6#y Co**on i!p@! !peci#l 'or*! c#n loo9 li9e regul#r 'unction c#ll!. :o6 you <u!t need to i*ple*ent process-special-(orm. $#ther th#n de'ine # !ingle *onolithic 'unction th#t i*ple*ent! #ll the !peci#l oper#tor!, you !hould de'ine # *#cro th#t #llo6! you to de'ine !peci#l oper#tor! *uch li9e regul#r 'unction! #nd th#t #l!o t#9e! c#re o' #dding the html-special-
operator entry to the property li!t o' the !peci#l oper#tor@! n#*e. In '#ct, the ?#lue you !tore in the property li!t c#n be # 'unction th#t i*ple*ent! the !peci#l oper#tor. >ere@! the *#cro:
1de(macro#de(ine-html-special-operator#1name#1processor#>rest#other-parameters3# >bod?#bod?3 ##B1eval-when#1:compile-toplevel#:load-toplevel#:e)ec'te3 #####1set(#1get#C5name#Chtml-special-operator3 ###########1lambda#15processor#5Pother-parameters3#5Pbod?3333
&hi! i! # '#irly #d?#nced type o' *#cro, but i' you t#9e it one line #t # ti*e, there@! nothing #ll th#t tric9y #bout it. &o !ee ho6 it 6or9!, t#9e # !i*ple u!e o' the *#cro, the de'inition o' the !peci#l oper#tor :noescape, #nd loo9 #t the *#cro e.p#n!ion. I' you 6rite thi!:
1de(ine-html-special-operator#:noescape#1processor#>rest#bod?3 ##1let#11UescapesU#nil33 ####1loop#(or#e)p#in#bod?#do#1process#processor#e)p3333
&he EVAL-WHEN !peci#l oper#tor, #! I di!cu!!ed in Ch#pter 20, en!ure! th#t the e''ect! o' code in it! body 6ill be *#de ?i!ible during co*pil#tion 6hen you co*pile 6ith COMPILE-FILE. &hi! *#tter! i' you 6#nt to u!e de(ine-html-special-operator in # 'ile #nd then u!e the <u!t-de'ined !peci#l oper#tor in th#t !#*e 'ile. &hen the SETF e.pre!!ion !et! the property html-special-operator on the !y*bol :noescape to #n #nony*ou! 'unction 6ith the !#*e p#r#*eter li!t #! 6#! !peci'ied in de(inehtml-special-operator. 7y de'ining de(ine-html-special-operator to !plit the p#r#*eter li!t in t6o p#rt!, processor #nd e?erything el!e, you en!ure th#t #ll !peci#l oper#tor! #ccept #t le#!t one #rgu*ent. &he body o' the #nony*ou! 'unction i! then the body pro?ided to de(ine-html-specialoperator. &he <ob o' the #nony*ou! 'unction i! to i*ple*ent the !peci#l oper#tor by *#9ing the #ppropri#te c#ll! on the b#c9end inter'#ce to gener#te the correct >&3 or the code th#t 6ill gener#te it. It c#n #l!o u!e process to e?#lu#te #n e.pre!!ion #! # /55 'or*. &he :noescape !peci#l oper#tor i! p#rticul#rly !i*ple--#ll it doe! i! p#!! the 'or*! in it! body to process 6ith UescapesU bound to NIL. In other 6ord!, thi! !peci#l oper#tor di!#ble! the nor*#l ch#r#cter e!c#ping pre'or*ed by process-se)p-html. With !peci#l oper#tor! de'ined thi! 6#y, #ll process-special-(orm h#! to do i! loo9 up the #nony*ou! 'unction in the property li!t o' the !peci#l oper#tor@! n#*e #nd APPLY it to the proce!!or #nd re!t o' the 'or*.
1de('n#process-special-(orm#1processor#(orm3 ##1appl?#1get#1car#(orm3#Chtml-special-operator3#processor#1rest#(orm333
:o6 you@re re#dy to de'ine the 'i?e re*#ining /55 !peci#l oper#tor!. Si*il#r to :noescape i! :attrib'te, 6hich e?#lu#te! the 'or*! in it! body 6ith UescapesU bound to Uattrib'teescapesU. &hi! !peci#l oper#tor i! u!e'ul i' you 6#nt to 6rite helper 'unction! th#t output #ttribute ?#lue!. I' you 6rite # 'unction li9e thi!:
1de('n#(oo-val'e#1something3 ##1html#1:print#1(rob#something3333
the html *#cro i! going to gener#te code th#t e!c#pe! the ch#r#cter! in Uelement-escapesU. 7ut i' you@re pl#nning to u!e (oo-val'e li9e thi!:
1html#1:p#:st?le#1(oo-val'e#4!3#4Eoo433
then you 6#nt it to gener#te code th#t u!e! Uattrib'te-escapesU. So, in!te#d, you c#n 6rite it li9e thi!:2
1de('n#(oo-val'e#1something3 ##1html#1:attrib'te#1:print#1(rob#something33333
&he ne.t t6o !peci#l oper#tor!, :print #nd :(ormat, #re u!ed to output ?#lue!. &he :print !peci#l oper#tor, #! I di!cu!!ed e#rlier, i! u!ed in co*piled /55 progr#*! to e*bed the ?#lue o' #n #rbitr#ry i!p e.pre!!ion. &he :(ormat !peci#l oper#tor i! *ore or le!! eFui?#lent to gener#ting # !tring 6ith 1(ormat#nil#...3 #nd then e*bedding it. &he pri*#ry re#!on to de'ine :(ormat #! # !peci#l oper#tor i! 'or con?enience. &hi!:
1:(ormat#4Eoo:#7d4#)3
It #l!o h#! the !light #d?#nt#ge th#t i' you u!e :(ormat 6ith #rgu*ent! th#t #re #ll !el'-e?#lu#ting, /55 c#n e?#lu#te the :(ormat #t co*pile ti*e r#ther th#n 6#iting until runti*e. &he de'inition! o' :print #nd :(ormat #re #! 'ollo6!:
1de(ine-html-special-operator#:print#1processor#(orm3 ##1cond ####11sel(-eval'ating-p#(orm3 #####1warn#4.ed'ndant#:print#o(#sel(-eval'ating#(orm#7s4#(orm3 #####1process-se)p-html#processor#(orm33 ####1t #####1embed-val'e#processor#(orm3333 1de(ine-html-special-operator#:(ormat#1processor#>rest#args3 ##1i(#1ever?#NCsel(-eval'ating-p#args3 ####1process-se)p-html#processor#1appl?#NC(ormat#nil#args33 ####1embed-val'e#processor#B1(ormat#nil#5Pargs3333
&he :newline !peci#l oper#tor 'orce! #n output o' # liter#l ne6line, 6hich i! occ#!ion#lly h#ndy.
1de(ine-html-special-operator#:newline#1processor3 ##1newline#processor33
/in#lly, the :progn !peci#l oper#tor i! #n#logou! to the PROGN !peci#l oper#tor in Co**on i!p. It !i*ply proce!!e! the 'or*! in it! body in !eFuence.
1de(ine-html-special-operator#:progn#1processor#>rest#bod?3 ##1loop#(or#e)p#in#bod?#do#1process#processor#e)p333
&hi! *ight !ee* li9e # !tr#nge thing to need !ince nor*#l /55 e.pre!!ion! c#n h#?e #ny nu*ber o' 'or*! in their body. >o6e?er, thi! !peci#l oper#tor 6ill co*e in Fuite h#ndy in one !itu#tion--6hen 6riting /55 *#cro!, 6hich bring! you to the l#!t l#ngu#ge 'e#ture you need to i*ple*ent.
F77 +acros
/55 *#cro! #re !i*il#r in !pirit to Co**on i!p@! *#cro!. % /55 *#cro i! # bit o' code th#t #ccept! # /55 e.pre!!ion #! #n #rgu*ent #nd return! # ne6 /55 e.pre!!ion #! the re!ult, 6hich i! then e?#lu#ted #ccording to the nor*#l /55 e?#lu#tion rule!. &he #ctu#l i*ple*ent#tion i! Fuite !i*il#r to the i*ple*ent#tion o' !peci#l oper#tor!. %! 6ith !peci#l oper#tor!, you c#n de'ine # predic#te 'unction to te!t 6hether # gi?en 'or* i! # *#cro 'or*.
1de('n#macro-(orm-p#1(orm3 ##1cons-(orm-p#(orm#NC1lambda#1)3#1and#1s?mbolp#)3#1get#)#Chtml-macro33333
4ou u!e the pre?iou!ly de'ined 'unction cons-(orm-p bec#u!e you 6#nt to #llo6 *#cro! to be u!ed in either o' the !ynt#.e! o' non*#cro /55 con! 'or*!. >o6e?er, you need to p#!! # di''erent predic#te 'unction, one th#t te!t! 6hether the 'or* n#*e i! # !y*bol 6ith # non-NIL html-macro property. %l!o, #! in the i*ple*ent#tion o' !peci#l oper#tor!, you@ll de'ine # *#cro 'or de'ining /55 *#cro!, 6hich i! re!pon!ible 'or !toring # 'unction in the property li!t o' the *#cro@! n#*e, under the 9ey html-macro. >o6e?er, de'ining # *#cro i! # bit *ore co*plic#ted bec#u!e /55 !upport! t6o 'l#?or! o' *#cro. So*e *#cro! you@ll de'ine 6ill beh#?e *uch li9e nor*#l >&3 ele*ent! #nd *#y 6#nt to h#?e e#!y #cce!! to # li!t o' #ttribute!. 5ther *#cro! 6ill !i*ply 6#nt r#6 #cce!! to the ele*ent! o' their body. 4ou c#n *#9e the di!tinction bet6een the t6o 'l#?or! o' *#cro! i*plicit: 6hen you de'ine # /55 *#cro, the p#r#*eter li!t c#n include #n >attrib'tes p#r#*eter. I' it doe!, the *#cro 'or* 6ill be p#r!ed li9e # regul#r con! 'or*, #nd the *#cro 'unction 6ill be p#!!ed t6o ?#lue!, # pli!t o' #ttribute! #nd # li!t o' e.pre!!ion! th#t *#9e up the body o' the 'or*. % *#cro 'or* 6ithout #n >attrib'tes p#r#*eter 6on@t be p#r!ed 'or #ttribute!, #nd the *#cro 'unction 6ill be in?o9ed 6ith # !ingle #rgu*ent, # li!t cont#ining the body e.pre!!ion!. &he 'or*er i! u!e'ul 'or 6h#t #re e!!enti#lly >&3 te*pl#te!. /or e.#*ple:
1de(ine-html-macro#:m?tag#1>attrib'tes#attrs#>bod?#bod?3 ##B11:div#:class#4m?tag4#5Pattrs3#5Pbod?33
&he l#tter 9ind o' *#cro i! *ore u!e'ul 'or 6riting *#cro! th#t *#nipul#te the 'or*! in their body. &hi! type o' *#cro c#n 'unction #! # 9ind o' >&3 control con!truct. %! # tri?i#l e.#*ple, con!ider the 'ollo6ing *#cro th#t i*ple*ent! #n :i( con!truct:
1de(ine-html-macro#:i(#1test#then#else3 ##B1i(#5test#1html#5then3#1html#5else333
&o deter*ine 6hich 9ind o' *#cro you !hould gener#te, you need # 'unction th#t c#n p#r!e the p#r#*eter li!t gi?en to de(ine-html-macro. &hi! 'unction return! t6o ?#lue!, the n#*e o' the >attrib'tes p#r#*eter, or NIL i' there 6#! none, #nd # li!t cont#ining #ll the ele*ent! o' args #'ter re*o?ing the >attrib'tes *#r9er #nd the !ub!eFuent li!t ele*ent.3
1de('n#parse-html-macro-lambda-list#1args3 ##1let#11attr-cons#1member#C>attrib'tes#args333 ####1val'es# #####1cadr#attr-cons3 #####1nconc#1ldi((#args#attr-cons3#1cddr#attr-cons33333 :F%L/#1parse-html-macro-lambda-list#C1a#b#c33 89L 1I#L#$3 :F%L/#1parse-html-macro-lambda-list#C1>attrib'tes#attrs#a#b#c33 IFF., 1I#L#$3 :F%L/#1parse-html-macro-lambda-list#C1a#b#c#>attrib'tes#attrs33 IFF., 1I#L#$3
&he ele*ent 'ollo6ing >attrib'tes in the p#r#*eter li!t c#n #l!o be # de!tructuring p#r#*eter li!t.
:F%L/#1parse-html-macro-lambda-list#C1>attrib'tes#1>&e?#)#?3#a#b#c33 1>M-H#[#H3 1I#L#$3
:o6 you@re re#dy to 6rite de(ine-html-macro. +epending on 6hether there 6#! #n >attrib'tes p#r#*eter !peci'ied, you need to gener#te one 'or* or the other o' >&3 *#cro !o the *#in *#cro !i*ply deter*ine! 6hich 9ind o' >&3 *#cro it@! de'ining #nd then c#ll! out to # helper 'unction to gener#te the right 9ind o' code.
1de(macro#de(ine-html-macro#1name#1>rest#args3#>bod?#bod?3 ##1m'ltiple-val'e-bind#1attrib'te-var#args3 ######1parse-html-macro-lambda-list#args3 ####1i(#attrib'te-var ######1generate-macro-with-attrib'tes#name#attrib'te-var#args#bod?3 ######1generate-macro-no-attrib'tes#name#args#bod?3333
&he 'unction! th#t #ctu#lly gener#te the e.p#n!ion loo9 li9e thi!:
1de('n#generate-macro-with-attrib'tes#1name#attrib'te-args#args#bod?3 ##1with-gens?ms#1attrib'tes#(orm-bod?3 ####1i(#1s?mbolp#attrib'te-args3#1set(#attrib'te-args#B1>rest#5attrib'te-args333 ####B1eval-when#1:compile-toplevel#:load-toplevel#:e)ec'te3 #######1set(#1get#C5name#Chtml-macro-wants-attrib'tes3#t3 #######1set(#1get#C5name#Chtml-macro3# #############1lambda#15attrib'tes#5(orm-bod?3 ###############1destr'ct'ring-bind#15Pattrib'te-args3#5attrib'tes #################1destr'ct'ring-bind#15Pargs3#5(orm-bod? ###################5Pbod?3333333 1de('n#generate-macro-no-attrib'tes#1name#args#bod?3 ##1with-gens?ms#1(orm-bod?3 ####B1eval-when#1:compile-toplevel#:load-toplevel#:e)ec'te3 #######1set(#1get#C5name#Chtml-macro-wants-attrib'tes3#nil3 #######1set(#1get#C5name#Chtml-macro3 #############1lambda#15(orm-bod?3 ###############1destr'ct'ring-bind#15Pargs3#5(orm-bod?#5Pbod?33333
&he *#cro 'unction! you@ll de'ine #ccept either one or t6o #rgu*ent! #nd then u!e DESTRUCTURING-BIND to t#9e the* #p#rt #nd bind the* to the p#r#*eter! de'ined in the c#ll to de(ine-html-macro. In both e.p#n!ion! you need to !#?e the *#cro 'unction in the n#*e@! property li!t under html-macro #nd # boole#n indic#ting 6hether the *#cro t#9e! #n >attrib'tes p#r#*eter under the property html-macro-wants-attrib'tes. 4ou u!e th#t property in the 'ollo6ing 'unction, e)pand-macro-(orm, to deter*ine ho6 the *#cro 'unction !hould be in?o9ed:
1de('n#e)pand-macro-(orm#1(orm3 ##1i(#1or#1consp#1(irst#(orm33 ##########1get#1(irst#(orm3#Chtml-macro-wants-attrib'tes33 ####1m'ltiple-val'e-bind#1tag#attrib'tes#bod?3#1parse-cons-(orm#(orm3 ######1('ncall#1get#tag#Chtml-macro3#attrib'tes#bod?33 ####1destr'ct'ring-bind#1tag#>bod?#bod?3#(orm ######1('ncall#1get#tag#Chtml-macro3#bod?3333
&he l#!t !tep i! to integr#te *#cro! by #dding # cl#u!e to the di!p#tching COND in the top-le?el process 'unction.
1de('n#process#1processor#(orm3 ##1cond ####11special-(orm-p#(orm3#1process-special-(orm#processor#(orm33 ####11macro-(orm-p#(orm3###1process#processor#1e)pand-macro-(orm#(orm333
/in#lly let@! loo9 #t html it!el'. &he only tric9y bit #bout i*ple*enting html co*e! 'ro* the need to gener#te code th#t c#n be u!ed to gener#te both pretty #nd co*p#ct output, depending on the runti*e ?#lue o' the ?#ri#ble Uprett?U. &hu!, html need! to gener#te #n e.p#n!ion th#t cont#in! #n IF e.pre!!ion #nd t6o ?er!ion! o' the code, one co*piled 6ith Uprett?U bound to true #nd one co*piled 6ith it bound to NIL. &o 'urther co*plic#te *#tter!, it@! co**on 'or one html c#ll to cont#in e*bedded c#ll! to html, li9e thi!:
1html#1:'l#1dolist#1item#st'((33#1html#1:li#item3333
I' the outer html e.p#nd! into #n IF e.pre!!ion 6ith t6o ?er!ion! o' the code, one 'or 6hen Uprett?U i! true #nd one 'or 6hen it@! '#l!e, it@! !illy 'or ne!ted html 'or*! to e.p#nd into t6o ?er!ion! too. In '#ct, it@ll le#d to #n e.ponenti#l e.plo!ion o' code !ince the ne!ted html i! #lre#dy going to be e.p#nded t6ice--once in the Uprett?U-i!-true br#nch #nd once in the Uprett?U-i!'#l!e br#nch. I' e#ch e.p#n!ion gener#te! t6o ?er!ion!, then you@ll h#?e 'our tot#l ?er!ion!. %nd i' the ne!ted html 'or* cont#ined #nother ne!ted html 'or*, you@d end up 6ith eight ?er!ion! o' th#t code. I' the co*piler i! !*#rt, it@ll e?entu#lly re#liAe th#t *o!t o' th#t gener#ted code i! de#d #nd 6ill eli*in#te it, but e?en 'iguring th#t out c#n t#9e Fuite # bit o' ti*e, !lo6ing do6n co*pil#tion o' #ny 'unction th#t u!e! ne!ted c#ll! to html. uc9ily, you c#n e#!ily #?oid thi! e.plo!ion o' de#d code by gener#ting #n e.p#n!ion th#t loc#lly rede'ine! the html *#cro, u!ing MACROLET, to gener#te only the right 9ind o' code. /ir!t you de'ine # helper 'unction th#t t#9e! the ?ector o' op! returned by se)p-/ops #nd run! it through optimi*e-static-o'tp't #nd generate-code--the t6o ph#!e! th#t #re #''ected by the ?#lue
o' Uprett?U--6ith Uprett?U bound to # !peci'ied ?#lue #nd th#t interpol#te! the re!ulting code into # PROGN. B&he PROGN return! NIL <u!t to 9eep thing! tidy.C.
1de('n#codegen-html#1ops#prett?3 ##1let#11Uprett?U#prett?33 ####B1progn#5P1generate-code#1optimi*e-static-o'tp't#ops33#nil333
With th#t 'unction, you c#n then de'ine html li9e thi!:
1de(macro#html#1>whole#whole#>bod?#bod?3 ##1declare#1ignore#bod?33 ##B1i(#Uprett?U #####1macrolet#11html#1>bod?#bod?3#1codegen-html#1se)p-/ops#bod?3#t333 #######1let#11Uhtml-prett?-printerU#1get-prett?-printer333#5whole33 #####1macrolet#11html#1>bod?#bod?3#1codegen-html#1se)p-/ops#bod?3#nil333 #######5whole333
&he &56o%' p#r#*eter repre!ent! the origin#l html 'or*, #nd bec#u!e it@! interpol#ted into the e.p#n!ion in the bodie! o' the t6o MACROLET!, it 6ill be reproce!!ed 6ith e#ch o' the ne6 de'inition! o' html, the one th#t gener#te! pretty-printing code #nd the other th#t gener#te! non-pretty-printing code. :ote th#t the ?#ri#ble Uprett?U i! u!ed both during *#cro e.p#n!ion and 6hen the re!ulting code i! run. It@! u!ed #t *#cro e.p#n!ion ti*e by codegen-html to c#u!e generate-code to gener#te one 9ind o' code or the other. %nd it@! u!ed #t runti*e, in the IF gener#ted by the top-le?el html *#cro, to deter*ine 6hether the pretty-printing or non-pretty-printing code !hould #ctu#lly run.
1&he
#n#logy bet6een /55@! !peci#l oper#tor!, #nd *#cro!, 6hich I@ll di!cu!! in the ne.t !ection, #nd i!p@! o6n i! '#irly !ound. In '#ct, under!t#nding ho6 /55@! !peci#l oper#tor! #nd *#cro! 6or9 *#y gi?e you !o*e in!ight into 6hy Co**on i!p i! put together the 6#y it i!.
2&he
:noescape #nd :attrib'te !peci#l oper#tor! *u!t be de'ined #! !peci#l oper#tor! bec#u!e /55 deter*ine! 6h#t e!c#pe! to u!e #t co*pile ti*e, not #t runti*e. &hi! #llo6! /55 to e!c#pe liter#l ?#lue! #t co*pile ti*e, 6hich i! *uch *ore e''icient th#n h#?ing to !c#n #ll output #t runti*e.
3:ote -&he
th#t >attrib'tes i! <u!t #nother !y*bolG there@! nothing intrin!ic#lly !peci#l #bout n#*e! th#t !t#rt 6ith >. one ele*ent o' the underlying l#ngu#ge-proce!!ing in'r#!tructure th#t@! not currently e.po!ed through !peci#l oper#tor! i! the indent#tion. I' you 6#nted to *#9e /55 *ore 'le.ible, #lbeit #t the co!t o' *#9ing it! %PI th#t *uch *ore co*ple., you could #dd !peci#l oper#tor! 'or *#nipul#ting the underlying indenting printer. 7ut it !ee*! li9e the co!t o' h#?ing to e.pl#in the e.tr# !peci#l oper#tor! 6ould out6eigh the r#ther !*#ll g#in in e.pre!!i?ene!!.
>&3 , connecting to rel#tion#l d#t#b#!e!, #nd building gr#phic#l inter'#ce! in ?#riou! 6#y!, #*ong other!. i!pWor9!, #nother pro*inent co**erci#l i!p, pro?ide! !e?er#l !i*il#r libr#rie!, including # 6ell-reg#rded port#ble =8I tool9it, C%PI, 6hich c#n be u!ed to de?elop =8I #pplic#tion! th#t 6ill run on #ny oper#ting !y!te* i!pWor9! run! on. &he 'ree #nd open-!ource Co**on i!p i*ple*ent#tion! typic#lly don@t include Fuite !o *#ny bundled libr#rie!, relying in!te#d on port#ble 'ree #nd open-!ource libr#rie!. 7ut e?en tho!e i*ple*ent#tion! u!u#lly 'ill in !o*e o' the *ore i*port#nt #re#! not #ddre!!ed by the l#ngu#ge !t#nd#rd !uch #! net6or9ing #nd *ultithre#ding. &he only di!#d?#nt#ge o' u!ing i*ple*ent#tion-!peci'ic libr#rie! i! th#t they tie you to the i*ple*ent#tion th#t pro?ide! the*. I' you@re deli?ering end-u!er #pp! or #re deploying # !er?er-b#!ed #pplic#tion on # !er?er th#t you control, th#t *#y not *#tter # lot. 7ut i' you 6#nt to 6rite code to !h#re 6ith other i!per! or i' you !i*ply don@t 6#nt to be tied to # p#rticul#r i*ple*ent#tion, it@! # little *ore #nnoying. /or port#ble libr#rie!--port#ble either bec#u!e they@re 6ritten entirely in !t#nd#rd Co**on i!p or bec#u!e they cont#in #ppropri#te re#d-ti*e condition#liA#tion to 6or9 on *ultiple i*ple*ent#tion!1-your be!t bet i! to go to the Web. With the u!u#l c#?e#t! #bout 8$ ! going !t#le #! !oon #! they@re printed on p#per, the!e #re three o' the be!t current !t#rting point!: Co**on- i!p.net Bhttp://www.common-lisp.net/C i! # !ite th#t ho!t! 'ree #nd open!ource Co**on i!p pro<ect!, pro?iding ?er!ion control, *#iling li!t!, #nd Web ho!ting o' pro<ect p#ge!. In the 'ir!t ye#r #nd # h#l' #'ter the !ite 6ent li?e, ne#rly # hundred pro<ect! 6ere regi!tered. &he Co**on i!p 5pen Code Collection BC 5CCC Bhttp://clocc.so'rce(orge.net/C i! # !lightly older collection o' 'ree !o't6#re libr#rie!, 6hich #re intended to be port#ble bet6een Co**on i!p i*ple*ent#tion! #nd !el'cont#ined, not relying on #ny libr#rie! not included in C 5CC it!el'. Cli9i Bhttp://www.cli&i.net/C i! # 6i9i de?oted to 'ree !o't6#re in Co**on i!p. While, li9e #ny 6i9i, it *#y ch#nge #t #ny ti*e, typic#lly it h#! Fuite # 'e6 lin9! to libr#rie! #! 6ell to ?#riou! open-!ource Co**on i!p i*ple*ent#tion!. &he epony*ou! !o't6#re it run! on i! #l!o 6ritten in Co**on i!p. inu. u!er! running the +ebi#n or =entoo di!tribution! c#n #l!o e#!ily in!t#ll #n e?er-gro6ing nu*ber o' i!p libr#rie! th#t h#?e been p#c9#ged 6ith tho!e di!tribution!@ p#c9ing tool!, apt-get on +ebi#n #nd emerge on =entoo. I 6on@t reco**end #ny !peci'ic libr#rie! here !ince the libr#ry !itu#tion i! ch#nging e?ery d#y--#'ter ye#r! o' en?ying the libr#ry collection! o' Perl, Python, #nd D#?#, Co**on i!per! h#?e, in the p#!t couple o' ye#r!, begun to t#9e up the ch#llenge o' gi?ing Co**on i!p the !et o' libr#rie!--both open !ource #nd co**erci#l--th#t it de!er?e!. 5ne #re# 6here there h#! been # lot o' #cti?ity recently i! on the =8I 'ront. 8nli9e D#?# #nd CI but li9e Perl, Python, #nd C, there@! no !ingle 6#y to de?elop =8I! in Co**on i!p. In!te#d, it depend! both on 6h#t Co**on i!p i*ple*ent#tion you@re u!ing #nd 6h#t oper#ting !y!te* or !y!te*! you 6#nt to !upport. &he co**erci#l Co**on i!p i*ple*ent#tion! u!u#lly pro?ide !o*e 6#y to build =8I! 'or the pl#t'or*! they run on. %ddition#lly, i!pWor9! pro?ide! C%PI, the pre?iou!ly *entioned, port#ble =8I %PI. 5n the open-!ource !ide, you h#?e # nu*ber o' option!. 5n 8ni., you c#n 6rite lo6-le?el N Windo6!
=8I! u!ing C N, # pure-Co**on i!p i*ple*ent#tion o' the N Windo6! protocol, roughly #9in to .lib in C. 5r you c#n u!e ?#riou! binding! to higher-le?el %PI! #nd tool9it! !uch #! =&L #nd &9, *uch the 6#y you *ight in Perl or Python. 5r, i' you@re loo9ing 'or !o*ething co*pletely di''erent, you c#n chec9 out Co**on i!p Inter'#ce 3#n#ger BC I3C. % de!cend#nt o' the Sy*bolic! i!p 3#chine! =8I 'r#*e6or9, C I3 i! po6er'ul but co*ple.. %lthough *#ny co**erci#l Co**on i!p i*ple*ent#tion! #ctu#lly !upport it, it doe!n@t !ee* to h#?e !een # lot o' u!e. 7ut in the p#!t couple ye#r!, #n open-!ource i*ple*ent#tion o' C I3, 3cC I3--no6 ho!ted #t Co**on- i!p.net--h#! been pic9ing up !te#* l#tely, !o 6e *#y be on the ?erge o' # C I3 ren#i!!#nce.
code i! to 'ind the right #lgorith*! #nd d#t# !tructure!. Co**on i!p@! dyn#*ic 'e#ture! 9eep code 'le.ible, 6hich *#9e! it e#!ier to try di''erent #ppro#che!. =i?en # 'inite #*ount o' ti*e to 6rite # progr#*, you@re *uch *ore li9ely to end up 6ith # highper'or*#nce ?er!ion i' you don@t !pend # lot o' ti*e getting into #nd out o' de#d end!. In Co**on i!p, you c#n try #n ide#, !ee it@! going no6here, #nd *o?e on 6ithout h#?ing !pent # ton o' ti*e con?incing the co*piler your code i! 6orthy o' being run #nd then 6#iting 'or it to 'ini!h co*piling. 4ou c#n 6rite # !tr#ight'or6#rd but ine''icient ?er!ion o' # 'unction--# code s$etch--to deter*ine 6hether your b#!ic #ppro#ch i! !ound #nd then repl#ce th#t 'unction 6ith # *ore co*ple. but *ore e''icient i*ple*ent#tion i' you deter*ine th#t it i!. %nd i' the o?er#ll #ppro#ch turn! out to be 'l#6ed, then you h#?en@t 6#!ted # bunch o' ti*e tuning # 'unction th#t@! no longer needed, 6hich *e#n! you h#?e *ore ti*e to 'ind # better #ppro#ch. &he ne.t re#!on Co**on i!p i! # good l#ngu#ge 'or de?eloping high-per'or*#nce !o't6#re i! th#t *o!t Co**on i!p i*ple*ent#tion! co*e 6ith *#ture co*piler! th#t gener#te Fuite e''icient *#chine code. I@ll t#l9 in # *o*ent #bout ho6 to help the!e co*piler! gener#te code th#t 6ill be co*petiti?e 6ith code gener#ted by C co*piler!, but the!e i*ple*ent#tion! #lre#dy #re Fuite # bit '#!ter th#n tho!e o' l#ngu#ge! 6ho!e i*ple*ent#tion! #re le!! *#ture #nd u!e !i*pler co*piler! or interpreter!. %l!o, !ince the i!p co*piler i! #?#il#ble #t runti*e, the i!p progr#**er h#! !o*e po!!ibilitie! th#t 6ould be h#rd to e*ul#te in other l#ngu#ge!--your progr#*! c#n gener#te i!p code #t runti*e th#t@! then co*piled into *#chine code #nd run. I' the gener#ted code i! going to run enough ti*e!, thi! c#n be # big 6in. 5r, e?en 6ithout u!ing the co*piler #t runti*e, clo!ure! gi?e you #nother 6#y to *eld *#chine code 6ith runti*e d#t#. /or in!t#nce, the C -PPC$( regul#r e.pre!!ion libr#ry, running in C38C , i! '#!ter th#n Perl@! regul#r e.pre!!ion engine on !o*e bench*#r9!, e?en though Perl@! engine i! 6ritten in highly tuned C. &hi! i! pre!u*#bly bec#u!e in Perl # regul#r e.pre!!ion i! tr#n!l#ted into 6h#t #re e!!enti#lly bytecode! th#t #re then interpreted by the rege. engine, 6hile C PPC$( tr#n!l#te! # regul#r e.pre!!ion into # tree o' co*piled clo!ure! th#t in?o9e e#ch other ?i# the nor*#l 'unction-c#lling *#chinery.5 >o6e?er, e?en 6ith the right #lgorith* #nd # high-Fu#lity co*piler, you *#y not get the r#6 !peed you need. &hen it@! ti*e to thin9 #bout pro'iling #nd tuning. &he 9ey, in i!p #! in #ny l#ngu#ge, i! to pro'ile 'ir!t to 'ind the !pot! 6here your progr#* i! #ctu#lly !pending it! ti*e #nd then 6orry #bout !peeding up tho!e p#rt!.0 4ou h#?e # nu*ber o' di''erent 6#y! to #ppro#ch pro'iling. &he l#ngu#ge !t#nd#rd pro?ide! # 'e6 rudi*ent#ry tool! 'or *e#!uring ho6 long cert#in 'or*! t#9e to e.ecute. In p#rticul#r, the TIME *#cro c#n be 6r#pped #round #ny 'or* #nd 6ill return 6h#te?er ?#lue! the 'or* return! #'ter printing # *e!!#ge to *TRACE-OUTPUT* #bout ho6 long it too9 to run #nd ho6 *uch *e*ory it u!ed. &he e.#ct 'or* o' the *e!!#ge i! i*ple*ent#tion de'ined. 4ou c#n u!e TIME 'or # bit o' Fuic9-#nd-dirty pro'iling to n#rro6 your !e#rch 'or bottlenec9!. /or in!t#nce, !uppo!e you h#?e # 'unction th#t@! t#9ing # long ti*e to run #nd th#t c#ll! t6o other 'unction!--!o*ething li9e thi!:
1de('n#(oo#13 ##1bar3 ##1ba*33
I' you 6#nt to !ee 6hether bar or ba* i! t#9ing *ore ti*e, you c#n ch#nge the de'inition o' (oo to thi!:
1de('n#(oo#13 ##1time#1bar33
##1time#1ba*333
:o6 you c#n c#ll (oo, #nd i!p 6ill print t6o report!, one 'or bar #nd one 'or ba*. &he 'or* i! i*ple*ent#tion dependentG here@! 6h#t it loo9! li9e in %llegro Co**on i!p:
$L-+,-./#1(oo3 S#cp'#time#1non-gc3#6 #msec#'ser5# #msec#s?stem S#cp'#time#1gc3##### #msec#'ser5# #msec#s?stem S#cp'#time#1total3##6 #msec#'ser5# #msec#s?stem S#real#time##0 "#msec S#space#allocation: S##!450Q!#cons#cells5#05696#other#b?tes5# #static#b?tes S#cp'#time#1non-gc3#"4 #msec#'ser5#0 #msec#s?stem S#cp'#time#1gc3#####0Q #msec#'ser5# #msec#s?stem S#cp'#time#1total3##Q0 #msec#'ser5#0 #msec#s?stem S#real#time##05 46#msec S#space#allocation: S##!Q 50Q!#cons#cells5#05696#other#b?tes5# #static#b?tes
5' cour!e, th#t@d be # bit e#!ier to re#d i' the output included # l#bel. I' you u!e thi! techniFue # lot, it *ight be 6orth de'ining your o6n *#cro li9e thi!:
1de(macro#labeled-time#1(orm3 ##B1progn ####1(ormat#Utrace-o'tp'tU#47!>7a4#C5(orm3 ####1time#5(orm333
I' you repl#ce TIME 6ith labeled-time in (oo, you@ll get thi! output:
$L-+,-./#1(oo3 1LI.3 S#cp'#time#1non-gc3#6 #msec#'ser5# #msec#s?stem S#cp'#time#1gc3##### #msec#'ser5# #msec#s?stem S#cp'#time#1total3##6 #msec#'ser5# #msec#s?stem S#real#time##030#msec S#space#allocation: S##!450Q!#cons#cells5#05696#other#b?tes5# #static#b?tes 1LI^3 S#cp'#time#1non-gc3#49 #msec#'ser5# #msec#s?stem S#cp'#time#1gc3#####09 #msec#'ser5#0 #msec#s?stem S#cp'#time#1total3##6R #msec#'ser5#0 #msec#s?stem S#real#time##05 RR#msec S#space#allocation: S##!Q 50Q!#cons#cells5#05696#other#b?tes5# #static#b?tes
/ro* thi! output, it@! cle#r th#t *o!t o' the ti*e in (oo i! !pent in ba*.
5' cour!e, the output 'ro* TIME get! # bit un6ieldy i' the 'or* you 6#nt to pro'ile i! c#lled repe#tedly. 4ou c#n build your o6n *e#!ure*ent tool! u!ing the 'unction! GET-INTERNAL-REALTIME #nd GET-INTERNAL-RUN-TIME, 6hich return # nu*ber th#t incre#!e! by the ?#lue o' the con!t#nt INTERNAL-TIME-UNITS-PER-SECOND e#ch !econd. GET-INTERNAL-REAL-TIME *e#!ure! wall time, the #ctu#l #*ount o' ti*e el#p!ed, 6hile GET-INTERNAL-RUN-TIME *e#!ure! !o*e i*ple*ent#tion-de'ined ?#lue !uch #! the #*ount o' ti*e i!p 6#! #ctu#lly e.ecuting or the ti*e i!p 6#! e.ecuting u!er code #nd not intern#l boo99eeping !uch #! the g#rb#ge collector. >ere@! # tri?i#l but u!e'ul pro'iling tool built 6ith # 'e6 *#cro! #nd GET-INTERNAL-RUN-TIME:
1de(parameter#Utiming-dataU#133 1de(macro#with-timing#1label#>bod?#bod?3 ##1with-gens?ms#1start3 ####B1let#115start#1get-internal-r'n-time333 ######1'nwind-protect#1progn#5Pbod?3 ########1p'sh#1list#C5label#5start#1get-internal-r'n-time33#Utiming-dataU33333 1de('n#clear-timing-data#13 ##1set(#Utiming-dataU#1333 1de('n#show-timing-data#13 ##1loop#(or#1label#time#co'nt#time-per#6-o(-total3#in#1compile-timing-data3#do #######1(ormat#t#473d6#7a:#7d#tic&s#over#7d#calls#(or#7d#per.764# ###############6-o(-total#label#time#co'nt#time-per333 1de('n#compile-timing-data#13# ##1loop#with#timing-table#=#1ma&e-hash-table3 #####with#co'nt-table#=#1ma&e-hash-table3 #####(or#1label#start#end3#in#Utiming-dataU #####(or#time#=#1-#end#start3 #####s'mming#time#into#total #####do #######1inc(#1gethash#label#timing-table# 3#time3 #######1inc(#1gethash#label#co'nt-table# 33 #####(inall?# #######1ret'rn #########1sort ##########1loop#(or#label#being#the#hash-&e?s#in#timing-table#collect ###############1let##11time#1gethash#label#timing-table33 ######################1co'nt#1gethash#label#co'nt-table333 #################1list#label#time#co'nt#1ro'nd#1/#time#co'nt33#1ro'nd#1U#0 time#total333333 ##########NC/#:&e?#NC(i(th3333
#1/#
&hi! pro'iler let! you 6r#p # with-timing #round #ny 'or*G e#ch ti*e the 'or* i! e.ecuted, the ti*e it !t#rt! #nd the ti*e it end! #re recorded, #!!oci#ting 6ith # l#bel you pro?ide. &he 'unction show-timing-data du*p! out # t#ble !ho6ing ho6 *uch ti*e 6#! !pent in di''erent l#beled !ection! o' code li9e thi!:
$L-+,-./#1show-timing-data3 #R46#LI.:#6" #tic&s#over#!#calls#(or#3!"#per. #066#E;;:#0! #tic&s#over#"#calls#(or#!4#per. 89L
4ou could ob?iou!ly *#9e thi! pro'iling code *ore !ophi!tic#ted in *#ny 6#y!. %ltern#ti?ely, your i!p i*ple*ent#tion *o!t li9ely pro?ide! it! o6n pro'iling tool!, 6hich, !ince they h#?e #cce!! to the intern#l! o' the i*ple*ent#tion, c#n get #t in'or*#tion not nece!!#rily #?#il#ble to u!er-le?el code. 5nce you@?e 'ound the bottlenec9 in your code, you c#n !t#rt tuning. &he 'ir!t thing you !hould try, o' cour!e, i! to 'ind # *ore e''icient b#!ic #lgorith*--th#t@! 6here the big g#in! #re to be h#d. 7ut #!!u*ing you@re #lre#dy u!ing #n #ppropri#te #lgorith*, then it@! do6n to code bumming--loc#lly opti*iAing the code !o it doe! #b!olutely no *ore 6or9 th#n nece!!#ry. &he *#in tool! 'or code bu**ing in Co**on i!p #re it! option#l decl#r#tion!. &he b#!ic ide# behind decl#r#tion! in Co**on i!p i! th#t they@re u!ed to gi?e the co*piler in'or*#tion it c#n u!e in # ?#riety o' 6#y! to gener#te better code. /or # !i*ple e.#*ple, con!ider thi! Co**on i!p 'unction:
1de('n#add#1)#?3#12#)#?33
I *entioned in Ch#pter 10 th#t i' you co*p#re the per'or*#nce o' thi! 'unction i!p to the !ee*ingly eFui?#lent C 'unction:
int#add#1int#)5#int#?3#V#ret'rn#)#2#?S#W
you@ll li9ely 'ind the Co**on i!p ?er!ion to be Fuite # bit !lo6er, e?en i' your Co**on i!p i*ple*ent#tion 'e#ture! # high-Fu#lity n#ti?e co*piler. &h#t@! bec#u!e the Co**on i!p ?er!ion i! doing # lot *ore--the Co**on i!p co*piler doe!n@t e?en 9no6 th#t the ?#lue! o' a #nd b #re nu*ber! #nd !o h#! to gener#te code to chec9 #t runti*e. %nd once it deter*ine! they are nu*ber!, it h#! to deter*ine 6h#t type! o' nu*ber!--integer!, r#tion#l!, 'lo#ting point, or co*ple.--#nd di!p#tch to the #ppropri#te #ddition routine 'or the #ctu#l type!. %nd e?en i' a #nd b #re integer!--the c#!e you c#re #bout--then the #ddition routine h#! to #ccount 'or the po!!ibility th#t the re!ult *#y be too l#rge to repre!ent #! # fi3num, # nu*ber th#t c#n be repre!ented in # !ingle *#chine 6ord, #nd thu! it *#y h#?e to #lloc#te # bignum ob<ect. In C, on the other h#nd, bec#u!e the type o' #ll ?#ri#ble! #re decl#red, the co*piler 9no6! e.#ctly 6h#t 9ind o' ?#lue! a #nd b 6ill hold. %nd bec#u!e C@! #rith*etic !i*ply o?er'lo6! 6hen the re!ult o' #n #ddition i! too l#rge to repre!ent in 6h#te?er type i! being returned, there@! no chec9ing 'or o?er'lo6 #nd no #lloc#tion o' # bignu* ob<ect to repre!ent the re!ult 6hen the *#the*#tic#l !u* i! too l#rge to 'it in # *#chine 6ord. &hu!, 6hile the beh#?ior o' the Co**on i!p code i! *uch *ore li9ely to be *#the*#tic#lly correct, the C ?er!ion c#n prob#bly be co*piled do6n to one or t6o *#chine in!truction!. 7ut i' you@re 6illing to gi?e the Co**on i!p co*piler the !#*e in'or*#tion the C co*piler h#! #bout the type! o' #rgu*ent! #nd return ?#lue! #nd to #ccept cert#in C-li9e co*pro*i!e! in ter*! o' gener#lity #nd error chec9ing, the Co**on i!p 'unction c#n #l!o be co*piled do6n to #n in!truction or t6o. &h#t@! 6h#t decl#r#tion! #re 'or. &he *#in u!e o' decl#r#tion! i! to tell the co*piler #bout the type! o' ?#ri#ble! #nd other e.pre!!ion!. /or in!t#nce, you could tell the co*piler th#t the #rgu*ent! to add #re both 'i.nu*! by 6riting the 'unction li9e thi!:
1de('n#add#1)#?3 ##1declare#1(i)n'm#)#?33 ##12#)#?33
&he DECLARE e.pre!!ion i!n@t # i!p 'or*G r#ther, it@! p#rt o' the !ynt#. o' the DEFUN #nd *u!t #ppe#r be'ore #ny other code in the 'unction body.2 &hi! decl#r#tion decl#re! th#t the #rgu*ent! p#!!ed
'or the p#r#*eter! ) #nd ? 6ill #l6#y! be 'i.nu*!. In other 6ord!, it@! # pro*i!e to the co*piler, #nd the co*piler i! #llo6ed to gener#te code on the #!!u*ption th#t 6h#te?er you tell it i! true. &o decl#re the type o' the ?#lue returned, you c#n 6r#p the 'or* 12#)#?3 in the THE !peci#l oper#tor. &hi! oper#tor t#9e! # type !peci'ier, !uch #! FIXNUM, #nd # 'or* #nd tell! the co*piler the 'or* 6ill e?#lu#te to the gi?en type. &hu!, to gi?e the Co**on i!p co*piler #ll the in'or*#tion #bout add th#t the C co*piler get!, you c#n 6rite it li9e thi!:
1de('n#add#1)#?3 ##1declare#1(i)n'm#)#?33 ##1the#(i)n'm#12#)#?333
>o6e?er, e?en thi! ?er!ion need! one *ore decl#r#tion to gi?e the Co**on i!p co*piler the !#*e licen!e #! the C co*piler to gener#te '#!t but d#ngerou! code. &he OPTIMI3E decl#r#tion i! u!ed to tell the co*piler ho6 to b#l#nce 'i?e Fu#litie!: the !peed o' the code gener#tedG the #*ount o' runti*e error chec9ingG the *e*ory u!#ge o' the code, both in ter*! o' code !iAe #nd runti*e *e*ory u!#geG the #*ount o' debugging in'or*#tion 9ept 6ith the codeG #nd the !peed o' the co*pil#tion proce!!. %n OPTIMI3E decl#r#tion con!i!t! o' one or *ore li!t!, e#ch cont#ining one o' the !y*bol! SPEED, SAFETY, SPACE, DEBUG, #nd COMPILATION-SPEED, #nd # nu*ber 'ro* Aero to three, inclu!i?e. &he nu*ber !peci'ie! the rel#ti?e 6eighting the co*piler !hould gi?e to the corre!ponding Fu#lity, 6ith 3 being the *o!t i*port#nt #nd *e#ning not i*port#nt #t #ll. &hu!, to *#9e Co**on i!p co*pile add *ore or le!! li9e # C co*piler 6ould, you c#n 6rite it li9e thi!:
1de('n#add#1)#?3 ##1declare#1optimi*e#1speed#33#1sa(et?# 333 ##1declare#1(i)n'm#)#?33 ##1the#(i)n'm#12#)#?333
5' cour!e, no6 the i!p ?er!ion !u''er! 'ro* *#ny o' the !#*e li#bilitie! #! the C ?er!ion--i' the #rgu*ent! p#!!ed #ren@t 'i.nu*! or i' the #ddition o?er'lo6!, the re!ult 6ill be *#the*#tic#lly incorrect or 6or!e. %l!o, i' !o*eone c#ll! add 6ith # 6rong nu*ber o' #rgu*ent!, it *#y not be pretty. &hu!, you !hould u!e the!e 9ind! o' decl#r#tion! only #'ter your progr#* i! 6or9ing correctly. %nd you !hould #dd the* only 6here pro'iling !ho6! they@ll *#9e # di''erence. I' you@re getting re#!on#ble per'or*#nce 6ithout the*, le#?e the* out. 7ut 6hen pro'iling !ho6! you # re#l hot !pot in your code #nd you need to tune it up, go #he#d. 7ec#u!e you c#n u!e decl#r#tion! thi! 6#y, it@! r#rely nece!!#ry to re6rite code in C <u!t 'or per'or*#nce re#!on!G //I! #re u!ed to #cce!! e.i!ting C code, but decl#r#tion! #re u!ed 6hen C-li9e per'or*#nce i! needed. 5' cour!e, ho6 clo!e you c#n get the per'or*#nce o' # gi?en piece o' Co**on i!p code to C #nd CEE depend! *o!tly on ho6 *uch li9e C you@re 6illing to *#9e it. %nother code-tuning tool built into i!p i! the 'unction DISASSEMBLE. &he e.#ct beh#?ior o' thi! 'unction i! i*ple*ent#tion dependent bec#u!e it depend! on ho6 the i*ple*ent#tion co*pile! code-6hether to *#chine code, bytecode!, or !o*e other 'or*. 7ut the b#!ic ide# i! th#t it !ho6! you the code gener#ted by the co*piler 6hen it co*piled # !peci'ic 'unction. &hu!, you c#n u!e DISASSEMBLE to !ee 6hether your decl#r#tion! #re h#?ing #ny e''ect on the code gener#ted. %nd i' your i!p i*ple*ent#tion u!e! # n#ti?e co*piler #nd you 9no6 your pl#t'or*@! #!!e*bly l#ngu#ge, you c#n get # pretty good !en!e o' 6h#t@! #ctu#lly going on 6hen you c#ll one o' your 'unction!. /or in!t#nce, you could u!e DISASSEMBLE to get # !en!e o' the di''erence bet6een the 'ir!t ?er!ion o' add, 6ith no decl#r#tion!, #nd the 'in#l ?er!ion. /ir!t, de'ine #nd co*pile the origin#l ?er!ion.
1de('n#add#1)#?3#12#)#?33
&hen, #t the $(P , c#ll DISASSEMBLE 6ith the n#*e o' the 'unction. In %llegro, it !ho6! the 'ollo6ing #!!e*bly-l#ngu#ge-li9e du*p o' the code gener#ted by the co*piler:
$L-+,-./#1disassemble#Cadd3 SS#disassembl?#o(#NOE'nction#I<</ SS#(ormals:#[#H SS#code#start:#N)Q3Q496(4: ### :#""#########p'shl##ebp ###0:#Rb#ec####movl#####ebp5esp ###3:#"6#########p'shl##esi ###4:#R3#ec#!4#s'bl#####esp5\36 ###Q:#R3#(9# !#cmpl#####ec)5\! ##0 :#Q4# !####j*#######04 ##0!:#cd#60####int######\9Q###S#,H,::F.IT-I.J-.. ##04:#R #Q(#cb# #cmpb##Dedi-"3G5\ ########S#,H,::$=98F-..+TF-T-8<98J ##0R:#Q4# !####j*#######!! ##! :#cd#64####int######\0 ##S#,H,::F.IT-,9J8IL-:9F ##!!:#Rb#dR####movl#####eb)5ea) ##!4:# b#da####orl######eb)5ed) ##!6:#(6#c3# 3#testb####bl5\3 ##!9:#Q"# e####jn*######4" ##30:#Rb#dR####movl#####eb)5ea) ##33:# 3#da####addl#####eb)5ed) ##3":#Q # R####jo#######4" ##3Q:#Rb#c3####movl#####ea)5eb) ##39:#(R#########clc ##4 :#c9#########leave ##40:#Rb#Q"#(c#movl#####esi5Debp-4G ##44:#c3#########ret ##4":#Rb#"(#R(#movl#####eb)5Dedi-003G####S#-[$L::2=!;T ##4R:#((#"Q#!Q#call#####UDedi239G###S#,H,::F.I%T-FW; ##"0:#eb#(3####jmp######4 ##"3:#9 #########nop S#8o#val'e
Cle#rly, there@! # bunch o' !tu'' going on here. I' you@re '#*ili#r 6ith .,0 #!!e*bly l#ngu#ge, you c#n prob#bly tell 6h#t. :o6 co*pile thi! ?er!ion o' add 6ith #ll the decl#r#tion!.
1de('n#add#1)#?3 ##1declare#1optimi*e#1speed#33#1sa(et?# 333 ##1declare#1(i)n'm#)#?33 ##1the#(i)n'm#12#)#?333
:o6 di!#!!e*ble add #g#in, #nd !ee i' the decl#r#tion! h#d #ny e''ect.
$L-+,-./#1disassemble#Cadd3 SS#disassembl?#o(#NOE'nction#I<</ SS#(ormals:#[#H SS#code#start:#N)Q3Q4dc34: ### :# 3#c!####addl#####ea)5ed) ###!:#(R#########clc ###3:#Rb#Q"#(c#movl#####esi5Debp-4G ###6:#c3#########ret ###Q:#9 #########nop S#8o#val'e
1e%i,ering App%ications
%nother topic o' pr#ctic#l i*port#nce, 6hich I didn@t t#l9 #bout el!e6here in the boo9, i! ho6 to deli?er !o't6#re 6ritten in i!p. &he *#in re#!on I neglected thi! topic i! bec#u!e there #re *#ny di''erent 6#y! to do it, #nd 6hich one i! be!t 'or you depend! on 6h#t 9ind o' !o't6#re you need to deli?er to 6h#t 9ind o' u!er 6ith 6h#t Co**on i!p i*ple*ent#tion. In thi! !ection I@ll gi?e #n o?er?ie6 o' !o*e o' the di''erent option!. I' you@?e 6ritten code you 6#nt to !h#re 6ith 'ello6 i!p progr#**er!, the *o!t !tr#ight'or6#rd 6#y to di!tribute it i! #! !ource code., 4ou c#n di!tribute # !i*ple libr#ry #! # !ingle !ource 'ile, 6hich progr#**er! c#n LOAD into their i!p i*#ge, po!!ibly #'ter co*piling it 6ith COMPILE-FILE. 3ore co*ple. libr#rie! or #pplic#tion!, bro9en up #cro!! *ultiple !ource 'ile!, po!e #n #ddition#l ch#llenge--in order to lo#d #nd co*pile the code, the 'ile! need to be lo#ded #nd co*piled in the correct order. /or in!t#nce, # 'ile cont#ining *#cro de'inition! *u!t be lo#ded be'ore you c#n co*pile 'ile! th#t u!e tho!e *#cro!. %nd # 'ile cont#ining DEFPAC+AGE 'or*! *u!t be lo#ded be'ore #ny 'ile! th#t u!e tho!e p#c9#ge! c#n e?en be READ. i!per! c#ll thi! the s0stem definition proble* #nd typic#lly h#ndle it 6ith tool! c#lled s0stem definition facilities or s0stem definition utilities, 6hich #re !o*e6h#t #n#logou! to build tool! !uch #! ma&e or ant. %! 6ith ma&e #nd ant, !y!te* de'inition tool! #llo6 you to !peci'y the dependencie! bet6een di''erent 'ile! #nd then t#9e c#re o' lo#ding #nd co*piling the 'ile! in the correct order 6hile trying to do only 6or9 th#t@! nece!!#ry--reco*piling only 'ile! th#t h#?e ch#nged, 'or e.#*ple. &he!e d#y! the *o!t 6idely u!ed !y!te* de'inition tool i! %S+/, 6hich !t#nd! 'or !nother -0stem Definition ,acilit0.) &he b#!ic ide# behind %S+/ i! th#t you de'ine !y!te*! in %S+ 'ile!, #nd %S+/ pro?ide! # nu*ber o' oper#tion! on !y!te*! !uch #! lo#ding the* or co*piling the*. % !y!te* c#n #l!o be de'ined to depend on other !y!te*!, 6hich 6ill be lo#ded #! nece!!#ry. /or in!t#nce, the 'ollo6ing !ho6! the content! o' html.asd, the %S+ 'ile 'or the /55 libr#ry 'ro* Ch#pter! 31 #nd 32:
1de(pac&age#:com.gigamon&e?s.html-s?stem#1:'se#:asd(#:cl33 1in-pac&age#:com.gigamon&e?s.html-s?stem3 1de(s?stem#html ##:name#4html4 ##:a'thor#4Teter#,eibel#OpeterPgigamon&e?s.com/4 ##:version#4 .04 ##:maintainer#4Teter#,eibel#OpeterPgigamon&e?s.com/4 ##:license#4L,<4 ##:description#4:F%L#and#$,,#generation#(rom#se)ps.4 ##:long-description#44 ##:components ##11:(ile#4pac&ages43 ###1:(ile#4html4#:depends-on#14pac&ages433 ###1:(ile#4css4#:depends-on#14pac&ages4#4html4333 ##:depends-on#1:macro-'tilities33
I' you #dd # !y*bolic lin9 to thi! 'ile 'ro* # directory li!ted in asd(:Ucentral-registr?U,10 then you c#n type thi!:
1asd(:operate#Casd(:load-op#:html3
to co*pile #nd lo#d the 'ile! pac&ages.lisp, html.lisp, #nd html-macros.lisp in the correct order #'ter 'ir!t *#9ing !ure the :macro-'tilities !y!te* h#! been co*piled #nd lo#ded. /or other e.#*ple! o' %S+ 'ile!, you c#n loo9 #t thi! boo9@! !ource code--the code 'ro* e#ch pr#ctic#l ch#pter i! de'ined #! # !y!te* 6ith #ppropri#te inter!y!te* dependencie! e.pre!!ed in the %S+ 'ile!. 3o!t 'ree #nd open-!ource Co**on i!p libr#rie! you@ll 'ind 6ill co*e 6ith #n %S+ 'ile. So*e 6ill u!e other !y!te* de'inition tool! !uch #! the !lightly older 3L:+(/S4S&(3 or e?en utilitie! de?i!ed by the libr#ry@! #uthor, but the tide !ee*! to be turning in the direction o' %S+/.11 5' cour!e, 6hile %S+/ *#9e! it e#!y 'or i!per! to in!t#ll i!p libr#rie!, it@! not *uch help i' you 6#nt to p#c9#ge #n #pplic#tion 'or #n end u!er 6ho doe!n@t 9no6 or c#re #bout i!p. I' you@re deli?ering # pure end-u!er #pplic#tion, pre!u*#bly you 6#nt to pro?ide !o*ething the u!er c#n do6nlo#d, in!t#ll, #nd run 6ithout h#?ing to 9no6 #nything #bout i!p. 4ou c#n@t e.pect the* to !ep#r#tely do6nlo#d #nd in!t#ll # i!p i*ple*ent#tion. %nd you 6#nt the* to be #ble to run your #pplic#tion <u!t li9e #ny other #pplic#tion--by double-clic9ing #n icon on Windo6! or 5S N or by typing the n#*e o' the progr#* #t the co**#nd line on 8ni.. >o6e?er, unli9e C progr#*!, 6hich c#n typic#lly rely on cert#in !h#red libr#rie! B+ ! on Windo6!C th#t *#9e up the C Hrunti*eH being pre!ent #! p#rt o' the oper#ting !y!te*, i!p progr#*! *u!t include # i!p runti*e, th#t i!, the !#*e progr#* you run 6hen you !t#rt i!p though perh#p! 6ith cert#in 'unction#lity not needed to run the #pplic#tion e.ci!ed. &o 'urther co*plic#te *#tter!, program i!n@t re#lly 6ell de'ined in i!p. %! you@?e !een throughout thi! boo9, the proce!! o' de?eloping !o't6#re in i!p i! #n incre*ent#l proce!! th#t in?ol?e! *#9ing ch#nge! to the !et o' de'inition! #nd d#t# li?ing in your i!p i*#ge. &he Hprogr#*H i! <u!t # p#rticul#r !t#te o' the i*#ge #rri?ed #t by lo#ding the .lisp or .(asl 'ile! th#t cont#in code th#t cre#te! the #ppropri#te de'inition! #nd d#t#. 4ou could, then, di!tribute # i!p #pplic#tion #! # i!p runti*e plu! # bunch o' /%S 'ile! #nd #n e.ecut#ble th#t !t#rt! the runti*e, lo#d! the /%S !, #nd !o*eho6 in?o9e! the #ppropri#te !t#rting 'unction. >o6e?er, !ince #ctu#lly lo#ding the /%S ! c#n t#9e !o*e ti*e, e!peci#lly i' they h#?e to do #ny co*put#tion to !et up the !t#te o' the 6orld, *o!t Co**on i!p i*ple*ent#tion! pro?ide # 6#y to dump an image--to !#?e the !t#te o' # running i!p to # 'ile c#lled #n image file or !o*eti*e! # core. When # i!p runti*e !t#rt!, the 'ir!t thing it doe! i! lo#d #n i*#ge 'ile, 6hich it c#n do in *uch le!! ti*e th#n it@d t#9e to re-cre#te the !t#te by lo#ding /%S 'ile!. :or*#lly the i*#ge 'ile i! # de'#ult i*#ge cont#ining only the !t#nd#rd p#c9#ge! de'ined by the l#ngu#ge #nd #ny e.tr#! pro?ided by the i*ple*ent#tion. 7ut 6ith *o!t i*ple*ent#tion!, you h#?e # 6#y to !peci'y # di''erent i*#ge 'ile. &hu!, in!te#d o' p#c9#ging #n #pp #! # i!p runti*e plu! # bunch o' /%S !, you c#n p#c9#ge it #! # i!p runti*e plu! # !ingle i*#ge 'ile cont#ining #ll the de'inition! #nd d#t# th#t *#9e up your #pplic#tion. &hen #ll you need i! # progr#* th#t l#unche! the i!p runti*e 6ith the #ppropri#te i*#ge 'ile #nd in?o9e! 6h#te?er 'unction !er?e! #! the entry point to the #pplic#tion. &hi! i! 6here thing! get i*ple*ent#tion #nd oper#ting-!y!te* dependent. So*e Co**on i!p i*ple*ent#tion!, in p#rticul#r the co**erci#l one! !uch #! %llegro #nd i!pWor9!, pro?ide tool! 'or building !uch #n e.ecut#ble. /or in!t#nce, %llegro@! (nterpri!e (dition pro?ide! # 'unction e)cl:generate-application th#t cre#te! # directory cont#ining the i!p runti*e #! # !h#red libr#ry, #n i*#ge 'ile, #nd #n e.ecut#ble th#t !t#rt! the runti*e 6ith the gi?en i*#ge. Si*il#rly, the i!pWor9! Pro'e!!ion#l (dition Hdeli?eryH *ech#ni!* #llo6! you to build !ingle-'ile e.ecut#ble! o' your progr#*!. 5n 8ni., 6ith the ?#riou! 'ree #nd open-!ource i*ple*ent#tion!, you c#n do e!!enti#lly the !#*e thing e.cept it@! prob#bly e#!ier to u!e # !hell !cript to !t#rt e?erything. %nd on 5S N thing! #re e?en better--!ince #ll #pplic#tion! on 5S N #re p#c9#ged #! .app bundle!,
6hich #re e!!enti#lly directorie! 6ith # cert#in !tructure, it@! not #ll th#t di''icult to p#c9#ge #ll the p#rt! o' # i!p #pplic#tion #! # double-clic9#ble .app bundle. 3i9el (?in!@! 7o!co tool *#9e! it e#!y to cre#te .app bundle! 'or #pplic#tion! running on 5pen3C . 5' cour!e, #nother popul#r 6#y to deli?er #pplic#tion! the!e d#y! i! #! !er?er-!ide #pplic#tion!. &hi! i! # niche 6here Co**on i!p c#n re#lly e.cel--you c#n pic9 # co*bin#tion o' oper#ting !y!te* #nd Co**on i!p i*ple*ent#tion th#t 6or9! 6ell 'or you, #nd you don@t h#?e to 6orry #bout p#c9#ging the #pplic#tion to be in!t#lled by #n end u!er. %nd Co**on i!p@! inter#cti?e debugging #nd de?elop*ent 'e#ture! *#9e it po!!ible to debug #nd upgr#de # li?e !er?er in 6#y! th#t either <u!t #ren@t po!!ible in # le!! dyn#*ic l#ngu#ge or 6ould reFuire you to build # lot o' !peci'ic in'r#!tructure.
!olid introduction to #rti'ici#l intelligence techniFue! 6hile te#ching Fuite # bit #bout ho6 to 6rite good Co**on i!p code, #nd the l#tter i! e!peci#lly good in it! tre#t*ent o' *#cro!. I' you@re the 9ind o' per!on 6ho li9e! to 9no6 ho6 thing! 6or9 do6n to the bit!, Lisp in -mall Pieces by Chri!ti#n Mueinnec BC#*bridge 8ni?er!ity Pre!!, 1))0C pro?ide! # nice blend o' progr#**ing l#ngu#ge theory #nd pr#ctic#l i!p i*ple*ent#tion techniFue!. While it@! pri*#rily 'ocu!ed on Sche*e r#ther th#n Co**on i!p, the !#*e principle! #pply. /or 'ol9! 6ho 6#nt # little *ore theoretic#l loo9 #t thing!--or 6ho <u!t 6#nt to 9no6 6h#t it@! li9e to be # 're!h*#n co*p !ci !tudent #t 3.I.&.---tructure and ;nterpretation of Computer Programs, Second (dition, by >#rold %bel!on, =er#ld D#y Su!!*#n, #nd Dulie Su!!*#n B3.I.&. Press< %>>H@ is a classic computer science te3t that uses -cheme to teach important programming concept!. %ny progr#**er c#n le#rn # lot 'ro* thi! boo9--<u!t re*e*ber th#t there #re i*port#nt di''erence! bet6een Sche*e #nd Co**on i!p. 5nce you@?e 6r#pped your *ind #round i!p, you *#y 6#nt to pl#ce it in # bit o' conte.t. Since no one c#n cl#i* to re#lly under!t#nd ob<ect orient#tion 6ho doe!n@t 9no6 !o*ething #bout S*#llt#l9, you *ight 6#nt to !t#rt 6ith -malltal$)/7: The Language by %dele =oldberg #nd +#?id $ob!on B%ddi!on We!ley, 1),)C, the !t#nd#rd introduction to the core o' S*#llt#l9. %'ter th#t, -malltal$ #est Practice Patterns by Lent 7ec9 BPrentice >#ll, 1))2C i! 'ull o' good #d?ice #i*ed #t S*#llt#l9er!, *uch o' 6hich i! #pplic#ble to #ny ob<ect-oriented l#ngu#ge. %nd #t the other end o' the !pectru*, Object)Oriented -oftware Construction by 7ertr#nd 3eyer BPrentice >#ll, 1))2C i! #n e.cellent e.po!ition o' the !t#tic l#ngu#ge *ind-!et 'ro* the in?entor o' (i''el, #n o't-o?erloo9ed de!cend#nt o' Si*ul# #nd %lgol. It cont#in! *uch 'ood 'or thought, e?en 'or progr#**er! 6or9ing 6ith dyn#*ic l#ngu#ge! !uch #! Co**on i!p. In p#rticul#r, 3eyer@! ide#! #bout +e!ign 7y Contr#ct c#n !hed # lot o' light on ho6 one ought to u!e Co**on i!p@! condition !y!te*. &hough not #bout co*puter! per !e, The Eisdom of Crowds: Eh0 the Man0 !re -marter Than the ,ew and Bow Collective Eisdom -hapes #usiness< +conomies< -ocieties< and 2ations by D#*e! Suro6iec9i B+oubled#y, 200-C cont#in! #n e.cellent #n!6er to the Fue!tion, HI' i!p@! !o gre#t ho6 co*e e?erybody i!n@t u!ing it"H See the !ection on HPl#n9-$o#d /e?erH !t#rting on p#ge 53. %nd 'in#lly, 'or !o*e 'un, #nd to le#rn #bout the in'luence i!p #nd i!per! h#?e h#d on h#c9er culture, dip into Bor re#d 'ro* co?er to co?erC The 2ew Bac$er(s Dictionar0, &hird (dition, co*piled by (ric S. $#y*ond B3I& Pre!!, 1))0C #nd b#!ed on the origin#l The Bac$er(s Dictionar0 edited by =uy Steele B>#rper ] $o6, 1),3C. 7ut don@t let #ll the!e !ugge!tion! inter'ere 6ith your progr#**ing--the only 6#y to re#lly le#rn # l#ngu#ge i! to u!e it. I' you@?e *#de it thi! '#r, you@re cert#inly re#dy to do th#t. >#ppy h#c9ingP
1&he
co*bin#tion o' Co**on i!p@! re#d-ti*e condition#liA#tion #nd *#cro! *#9e! it Fuite 'e#!ible to de?elop port#bility libr#rie! th#t do nothing but pro?ide # co**on %PI l#yered o?er 6h#te?er %PI di''erent i*ple*ent#tion! pro?ide 'or '#cilitie! not !peci'ied in the l#ngu#ge !t#nd#rd. &he port#ble p#thn#*e libr#ry 'ro* Ch#pter 15 i! #n e.#*ple o' thi! 9ind o' libr#ry, #lbeit to !*ooth o?er di''erence! in interpret#tion o' the !t#nd#rd r#ther th#n i*ple*ent#tion-dependent %PI!.
2% /oreign 3%!
/unction Inter'#ce i! b#!ic#lly eFui?#lent to D:I in D#?#, NS in Perl, or the e.ten!ion *odule %PI in Python. o' thi! 6riting, the t6o *#in dr#6b#c9! o' 8//I #re the l#c9 o' !upport 'or c#llb#c9! 'ro* C into
i!p, 6hich *#ny but not #ll i*ple*ent#tion!@ //I! !upport, #nd the l#c9 o' !upport 'or C ISP, 6ho!e //I i! Fuite good but di''erent enough 'ro* the other! #! to not 'it e#!ily into the 8//I *odel.
-Lnuth
h#! u!ed the !#ying !e?er#l ti*e! in public#tion!, including in hi! 1)2- %C3 &uring %6#rd p#per, HCo*puter Progr#**ing #! #n %rt,H #nd in hi! p#per HStructured Progr#*! 6ith goto St#te*ent!.H In hi! p#per H&he (rror! o' &eN,H he #ttribute! the !#ying to C.%.$. >o#re. %nd >o#re, in #n 200- e-*#il to >#n! =en6itA o' phobi#.co*, !#id he didn@t re*e*ber the origin o' the !#ying but th#t he *ight h#?e #ttributed it to +i<9!tr#.
5C
-PPC$( #l!o t#9e! #d?#nt#ge o' #nother Co**on i!p 'e#ture I h#?en@t di!cu!!ed, compiler macros. % co*piler *#cro i! # !peci#l 9ind o' *#cro th#t@! gi?en # ch#nce to opti*iAe c#ll! to # !peci'ic 'unction by tr#n!'or*ing c#ll! to th#t 'unction into *ore e''icient code. C -PPC$( de'ine! co*piler *#cro! 'or it! 'unction! th#t t#9e regul#r e.pre!!ion #rgu*ent!. &he co*piler *#cro! opti*iAe c#ll! to tho!e 'unction! in 6hich the regul#r e.pre!!ion i! # con!t#nt ?#lue by p#r!ing the regul#r e.pre!!ion #t co*pile ti*e r#ther th#n le#?ing it to be done #t runti*e. oo9 up DEFINE-COMPILER-MACRO in your '#?orite Co**on i!p re'erence 'or *ore in'or*#tion #bout co*piler *#cro!.
0&he
6ord premature in Hpre*#ture opti*iA#tionH c#n pretty *uch be de'ined #! Hbe'ore pro'iling.H $e*e*ber th#t e?en i' you c#n !peed up # piece o' code to the point 6here it t#9e! liter#lly no ti*e to run, you@ll !till !peed up your progr#* only by 6h#te?er percent#ge o' ti*e it !pent in th#t piece o' code.
2+ecl#r#tion!
c#n #ppe#r in *o!t 'or*! th#t introduce ne6 ?#ri#ble!, !uch #! LET, LET*, #nd the DO '#*ily o' looping *#cro!. LOOP h#! it! o6n !ynt#. 'or decl#ring the type! o' loop ?#ri#ble!. &he !peci#l oper#tor LOCALLY, *entioned in Ch#pter 20, doe! nothing but cre#te # !cope in 6hich you c#n *#9e decl#r#tion!.
,&he
/%S 'ile! produced by COMPILE-FILE #re i*ple*ent#tion dependent #nd *#y or *#y not be co*p#tible bet6een di''erent ?er!ion! o' the !#*e Co**on i!p i*ple*ent#tion. &hu!, they@re not # ?ery good 6#y to di!tribute i!p code. &he one ti*e they c#n be h#ndy i! #! # 6#y o' pro?iding p#tche! to be #pplied to #n #pplic#tion running in # 9no6n ?er!ion o' # p#rticul#r i*ple*ent#tion. %pplying the p#tch !i*ply ent#il! LOADing the /%S , #nd bec#u!e # /%S c#n cont#in #rbitr#ry code, it c#n be u!ed to upgr#de e.i!ting d#t# #! 6ell #! to pro?ide ne6 code de'inition!.
)%S+/
6#! origin#lly 6ritten by +#niel 7#rlo6, one o' the S7C de?eloper!, #nd h#! been included #! p#rt o' S7C 'or # long ti*e #nd #l!o di!tributed #! # !t#nd-#lone libr#ry. It h#! recently been #dopted #nd included in other i*ple*ent#tion! !uch #! 5pen3C #nd %llegro.
105n Windo6!, 11%nother
6here there #re no !y*bolic lin9!, it 6or9! # little bit di''erently but roughly the !#*e.
tool, %S+/-I:S&% , build! on top o' %S+/ #nd 3L:+(/S4S&(3, pro?iding #n e#!y 6#y to #uto*#tic#lly do6nlo#d #nd in!t#ll libr#rie! 'ro* the net6or9. &he be!t !t#rting point 'or le#rning #bout %S+/-I:S&% i! (di WeitA@! H% tutori#l 'or %S+/-I:S&% H Bhttp://# www.weit*.de/asd(-install/C.
12S
I3( incorpor#te! #n (li!p libr#ry th#t #llo6! you to #uto*#tic#lly <u*p to the >yperSpec entry 'or #ny n#*e de'ined in the !t#nd#rd. 4ou c#n #l!o do6nlo#d # co*plete copy o' the >yperSpec to 9eep loc#lly 'or o''line bro6!ing.
13%nother
cl#!!ic re'erence i! Common Lisp: The Language by =uy Steele B+igit#l Pre!!, 1),- #nd 1))0C. &he 'ir!t edition, #.9.#. C t 1, 6#! the de '#cto !t#nd#rd 'or the l#ngu#ge 'or # nu*ber o' ye#r!. While 6#iting 'or the o''ici#l %:SI !t#nd#rd to be 'ini!hed, =uy Steele--6ho 6#! on the %:SI co**ittee--decided to rele#!e # !econd edition to bridge the g#p bet6een C t 1 #nd the e?entu#l
!t#nd#rd. &he !econd edition, no6 9no6n #! C t 2, i! e!!enti#lly # !n#p!hot o' the 6or9 o' the !t#nd#rdiA#tion co**ittee t#9en #t # p#rticul#r *o*ent in ti*e ne#r to, but not Fuite #t, the end o' the !t#nd#rdiA#tion proce!!. Con!eFuently, C t 2 di''er! 'ro* the !t#nd#rd in 6#y! th#t *#9e it not # ?ery good d#y-to-d#y re'erence. It i!, ho6e?er, # u!e'ul hi!toric#l docu*ent, p#rticul#rly bec#u!e it include! docu*ent#tion o' !o*e 'e#ture! th#t 6ere dropped 'ro* the !t#nd#rd be'ore it 6#! 'ini!hed #! 6ell #! co**ent#ry th#t i!n@t p#rt o' the !t#nd#rd #bout 6hy cert#in 'e#ture! #re the 6#y they #re.