Harold Abelson a Gerald Jay Sussman gyda Julie Sussman · Cyfieithiad Cymraeg
Fel y gwelsom, mae parau’n darparu “glud” cyntefig y gallwn ei ddefnyddio i adeiladu gwrthrychau data cyfansawdd. Mae Ffigur 2.2 yn dangos ffordd safonol o ddelweddu pâr—yn yr achos hwn, y pâr a ffurfiwyd gan (cons 1 2). Yn y cynrychioliad hwn, a elwir yn nodiant blychau a phwyntyddion, dangosir pob gwrthrych fel pwyntydd at flwch. Mae’r blwch ar gyfer gwrthrych cyntefig yn cynnwys cynrychioliad o’r gwrthrych. Er enghraifft, mae’r blwch ar gyfer rhif yn cynnwys rhifolyn. Mae’r blwch ar gyfer pâr mewn gwirionedd yn flwch dwbl: mae’r rhan chwith yn cynnwys (pwyntydd at) car y pâr, a’r rhan dde yn cynnwys yr cdr.
Ffigur 2.2: Cynrychioliad blychau a phwyntyddion o (cons 1 2).
Rydym eisoes wedi gweld y gellir defnyddio cons i gyfuno parau yn ogystal â rhifau. (Defnyddiasoch y ffaith hon, neu dylech fod wedi gwneud hynny, wrth wneud Ymarfer 2.2 ac Ymarfer 2.3.) O ganlyniad, mae parau’n darparu bloc adeiladu cyffredinol y gallwn adeiladu pob math o strwythurau data ohono. Mae Ffigur 2.3 yn dangos dwy ffordd o ddefnyddio parau i gyfuno’r rhifau 1, 2, 3, a 4.
Ffigur 2.3: Dwy ffordd o gyfuno 1, 2, 3, a 4 drwy ddefnyddio parau.
Y gallu i greu parau y mae eu helfennau’n barau yw hanfod pwysigrwydd strwythur rhestr fel offeryn cynrychioli. Cyfeiriwn at y gallu hwn fel priodwedd caucons. Yn gyffredinol, mae gweithrediad ar gyfer cyfuno gwrthrychau data yn bodloni’r briodwedd cau os gellir cyfuno canlyniadau cyfuno pethau â’r gweithrediad hwnnw eu hunain drwy ddefnyddio’r un gweithrediad.72 Y briodwedd cau yw’r allwedd i rym mewn unrhyw fodd o gyfuno, oherwydd mae’n caniatáu inni greu strwythurau hierarchaidd—strwythurau sy’n cynnwys rhannau, sydd eu hunain yn cynnwys rhannau, ac yn y blaen.
O ddechrau Pennod 1, rydym wedi gwneud defnydd hanfodol o’r briodwedd cau wrth ymdrin â gweithdrefnau, oherwydd mae pob rhaglen heblaw’r rhai symlaf oll yn dibynnu ar y ffaith y gall elfennau cyfuniad eu hunain fod yn gyfuniadau. Yn yr adran hon, awn i’r afael â chanlyniadau’r briodwedd cau ar gyfer data cyfansawdd. Disgrifiwn rai technegau confensiynol ar gyfer defnyddio parau i gynrychioli dilyniannau a choed, a dangoswn iaith graffeg sy’n darlunio’r briodwedd cau mewn ffordd fywiog.73
2.2.1Cynrychioli Dilyniannau
Un o’r strwythurau defnyddiol y gallwn eu hadeiladu â pharau yw dilyniant—casgliad trefnedig o wrthrychau data. Wrth gwrs, mae llawer o ffyrdd o gynrychioli dilyniannau yn nhermau parau. Dangosir un cynrychioliad arbennig o syml yn Ffigur 2.4, lle cynrychiolir y dilyniant 1, 2, 3, 4 fel cadwyn o barau. Yr car ym mhob pâr yw’r eitem gyfatebol yn y gadwyn, ac cdr y pâr yw’r pâr nesaf yn y gadwyn. Mae cdr y pâr olaf yn dynodi diwedd y dilyniant drwy bwyntio at werth neilltuol nad yw’n bâr, a gynrychiolir mewn diagramau blychau a phwyntyddion fel llinell groeslinol ac mewn rhaglenni fel gwerth y newidyn nil. Adeiladir y dilyniant cyfan drwy weithrediadau cons nythol:
(cons 1
(cons 2
(cons 3
(cons 4 nil))))
Ffigur 2.4: Y dilyniant 1, 2, 3, 4 wedi’i gynrychioli fel cadwyn o barau.
Gelwir dilyniant o barau o’r fath, a ffurfir gan alwadau cons nythol, yn rhestr, ac mae Scheme yn darparu gweithdrefn gyntefig o’r enw list i helpu i adeiladu rhestrau.74 Gellid cynhyrchu’r dilyniant uchod drwy (list 1 2 3 4). Yn gyffredinol, mae
(list ⟨a₁⟩ ⟨a₂⟩ … ⟨aₙ⟩)
yn gyfwerth â
(cons ⟨a₁⟩
(cons ⟨a₂⟩
(cons …
(cons ⟨aₙ⟩
nil)…)))
Yn ôl y confensiwn, mae systemau Lisp yn argraffu rhestrau drwy argraffu’r dilyniant o elfennau, wedi’i amgáu mewn cromfachau crwn. Felly, argreffir y gwrthrych data yn Ffigur 2.4 fel (1 2 3 4):
Byddwch yn ofalus i beidio â chymysgu’r mynegiad (list 1 2 3 4) â’r rhestr (1 2 3 4), sef y canlyniad a geir pan werthusir y mynegiad. Bydd ceisio gwerthuso’r mynegiad (1 2 3 4) yn arwyddo gwall pan fydd y dehonglydd yn ceisio cymhwyso’r weithdrefn 1 i’r argiau 2, 3, 4.
Gallwn ystyried car yn dethol yr eitem gyntaf yn y rhestr, ac cdr yn dethol yr isrestr sy’n cynnwys pob eitem heblaw’r gyntaf. Gellir defnyddio cymwysiadau nythol o car ac cdr i echdynnu’r ail, y drydedd, a’r eitemau dilynol yn y rhestr.75 Mae’r adeiladydd cons yn creu rhestr fel yr un wreiddiol, ond ag eitem ychwanegol ar y dechrau.
Gellir ystyried gwerth nil, a ddefnyddir i derfynu’r gadwyn o barau, yn ddilyniant heb elfennau, y rhestr wag. Mae’r gair nil yn dalfyriad o’r gair Lladin nihil, sy’n golygu “dim.”76
Gweithrediadau rhestr
Gyda’r defnydd o barau i gynrychioli dilyniannau o elfennau fel rhestrau, ceir technegau rhaglennu confensiynol ar gyfer trin rhestrau drwy gymhwyso “cdr” yn olynol i fynd i lawr y rhestrau. Er enghraifft, mae’r weithdrefn list-ref yn cymryd rhestr a rhif fel argiau ac yn dychwelyd eitem y rhestr. Yr arfer yw rhifo elfennau’r rhestr gan ddechrau gyda 0. Dyma’r dull o gyfrifo list-ref:
Ar gyfer , dylai list-ref ddychwelyd car y rhestr.
Fel arall, dylai list-ref ddychwelyd eitem rhif o cdr y rhestr.
Yn aml cymhwyswn cdr i fynd i lawr y rhestr gyfan. I gynorthwyo hyn, mae Scheme yn cynnwys traethiad cyntefig null?, sy’n profi a yw ei arg yn rhestr wag. Mae’r weithdrefn length, sy’n dychwelyd nifer yr eitemau mewn rhestr, yn dangos y patrwm defnydd nodweddiadol hwn:
Mae’r weithdrefn length yn gweithredu cynllun dychweliadol syml. Y cam lleihau yw:
Mae length unrhyw restr yn 1 ynghyd ag lengthcdr y rhestr.
Cymhwysir hyn yn olynol nes inni gyrraedd yr achos sylfaenol:
Mae length y rhestr wag yn 0.
Gallem hefyd gyfrifo length mewn arddull iteru:
(define (length items)
(define (length-iter a count)
(if (null? a)
count
(length-iter (cdr a)
(+ 1 count))))
(length-iter items 0))
Techneg raglennu gonfensiynol arall yw adeiladu rhestr ateb â “cons” wrth gymhwyso cdr i fynd i lawr rhestr, fel yn y weithdrefn append, sy’n cymryd dwy restr fel argiau ac yn cyfuno eu helfennau i wneud rhestr newydd:
Ymarfer 2.17: Diffiniwch weithdrefn last-pair sy’n dychwelyd y rhestr sy’n cynnwys elfen olaf rhestr benodol (nad yw’n wag) yn unig:
(last-pair (list 23 72 149 34))
(34)
Ymarfer 2.18: Diffiniwch weithdrefn reverse sy’n cymryd rhestr fel arg ac yn dychwelyd rhestr o’r un elfennau yn y drefn wrthdro:
(reverse (list 1 4 9 16 25))
(25 16 9 4 1)
Ymarfer 2.19: Ystyriwch y rhaglen cyfrif newid yn 1.2.2. Byddai’n braf gallu newid yn hawdd yr arian cyfred a ddefnyddir gan y rhaglen, fel y gallem gyfrifo nifer y ffyrdd o newid punt Brydeinig, er enghraifft. Fel y mae’r rhaglen wedi’i hysgrifennu, mae’r wybodaeth am yr arian cyfred wedi’i dosbarthu’n rhannol i’r weithdrefn first-denomination ac yn rhannol i’r weithdrefn count-change (sy’n gwybod bod pum math o ddarn arian yn UDA). Byddai’n well gallu darparu rhestr o ddarnau arian i’w defnyddio i roi newid.
Rydym eisiau ailysgrifennu’r weithdrefn cc fel bod ei hail arg yn rhestr o werthoedd y darnau arian i’w defnyddio, yn hytrach na chyfanrif sy’n pennu pa ddarnau arian i’w defnyddio. Gallem wedyn gael rhestrau a fyddai’n diffinio pob math o arian cyfred:
Diffiniwch y gweithdrefnau first-denomination, except-first-denomination ac no-more? yn nhermau gweithrediadau cyntefig ar strwythurau rhestr. A yw trefn y rhestr coin-values yn effeithio ar yr ateb a gynhyrchir gan cc? Pam, neu pam lai?
Ymarfer 2.20: Mae’r gweithdrefnau +, *, ac list yn cymryd nifer mympwyol o argiau. Un ffordd o ddiffinio gweithdrefnau o’r fath yw defnyddio define gyda nodiant cynffon ddotiog. Mewn diffiniad gweithdrefn, mae rhestr baramedrau sydd â dot cyn enw’r paramedr olaf yn dynodi, pan elwir y weithdrefn, y bydd gwerthoedd y paramedrau cychwynnol (os oes rhai) yn argiau cychwynnol, fel arfer, ond y bydd gwerth y paramedr olaf yn rhestr o unrhyw argiau sy’n weddill. Er enghraifft, o gael y diffiniad
(define (f x y . z) ⟨body⟩)
gellir galw’r weithdrefn f â dau arg neu fwy. Os gwerthuswn
(f 1 2 3 4 5 6)
yna yng nghorff f, bydd x yn 1, bydd y yn 2, a bydd z yn rhestr (3 4 5 6). O gael y diffiniad
(define (g . w) ⟨body⟩)
gellir galw’r weithdrefn g â sero neu fwy o argiau. Os gwerthuswn
(g 1 2 3 4 5 6)
yna yng nghorff g, bydd w yn rhestr (1 2 3 4 5
6).77
Defnyddiwch y nodiant hwn i ysgrifennu gweithdrefn same-parity sy’n cymryd un cyfanrif neu fwy ac yn dychwelyd rhestr o’r holl argiau sydd â’r un paredd eilrif-odrif â’r arg cyntaf. Er enghraifft,
Un gweithrediad hynod ddefnyddiol yw cymhwyso rhyw drawsffurfiad i bob elfen mewn rhestr a chynhyrchu’r rhestr o ganlyniadau. Er enghraifft, mae’r weithdrefn ganlynol yn graddio pob rhif mewn rhestr gan ffactor penodol:
Gallwn haniaethu’r syniad cyffredinol hwn a’i ddal fel patrwm cyffredin wedi’i fynegi fel gweithdrefn trefn uwch, yn union fel yn 1.3. Gelwir y weithdrefn trefn uwch yma yn map. Mae Map yn cymryd gweithdrefn un arg a rhestr fel argiau, ac yn dychwelyd rhestr o’r canlyniadau a gynhyrchir drwy gymhwyso’r weithdrefn i bob elfen yn y rhestr:78
Mae Map yn luniad pwysig, nid yn unig oherwydd ei fod yn dal patrwm cyffredin, ond oherwydd ei fod yn sefydlu lefel uwch o haniaethu wrth ymdrin â rhestrau. Yn y diffiniad gwreiddiol o scale-list, mae strwythur dychweliadol y rhaglen yn tynnu sylw at brosesu’r rhestr fesul elfen. Mae diffinio scale-list yn nhermau map yn cuddio’r lefel honno o fanylder ac yn pwysleisio bod graddio’n trawsffurfio rhestr o elfennau yn rhestr o ganlyniadau. Nid y gwahaniaeth rhwng y ddau ddiffiniad yw bod y cyfrifiadur yn cyflawni proses wahanol (nid yw), ond ein bod yn meddwl am y broses yn wahanol. I bob pwrpas, mae map yn helpu i sefydlu rhwystr haniaethu sy’n ynysu gweithrediad gweithdrefnau sy’n trawsffurfio rhestrau oddi wrth fanylion sut yr echdynnir ac y cyfunir elfennau’r rhestr. Fel y rhwystrau a ddangosir yn Ffigur 2.1, mae’r haniaeth hon yn rhoi’r hyblygrwydd inni newid manylion lefel isel gweithredu dilyniannau, gan gadw’r fframwaith cysyniadol o weithrediadau sy’n trawsffurfio dilyniannau yn ddilyniannau. Mae Adran 2.2.3 yn ymhelaethu ar y defnydd hwn o ddilyniannau fel fframwaith ar gyfer trefnu rhaglenni.
Ymarfer 2.21: Mae’r weithdrefn square-list yn cymryd rhestr o rifau fel arg ac yn dychwelyd rhestr o sgwariau’r rhifau hynny.
(square-list (list 1 2 3 4))
(1 4 9 16)
Dyma ddau ddiffiniad gwahanol o square-list. Cwblhewch y ddau drwy lenwi’r mynegiadau coll:
Ymarfer 2.23: Mae’r weithdrefn for-each yn debyg i map. Mae’n cymryd gweithdrefn a rhestr o elfennau fel argiau. Fodd bynnag, yn hytrach na ffurfio rhestr o’r canlyniadau, mae for-each yn cymhwyso’r weithdrefn i bob un o’r elfennau yn ei thro, o’r chwith i’r dde. Ni ddefnyddir y gwerthoedd a ddychwelir drwy gymhwyso’r weithdrefn i’r elfennau o gwbl—defnyddir for-each gyda gweithdrefnau sy’n cyflawni gweithred, megis argraffu. Er enghraifft,
Gall y gwerth a ddychwelir gan yr alwad i for-each (nas dangosir uchod) fod yn rhywbeth mympwyol, megis gwir. Rhowch weithrediad o for-each.
2.2.2Strwythurau Hierarchaidd
Mae cynrychioli dilyniannau yn nhermau rhestrau yn cyffredinoli’n naturiol i gynrychioli dilyniannau y gall eu helfennau eu hunain fod yn ddilyniannau. Er enghraifft, gallwn ystyried y gwrthrych ((1 2) 3 4) a adeiladir gan
(cons (list 1 2) (list 3 4))
yn rhestr o dair eitem, y mae’r gyntaf ei hun yn rhestr, (1 2). Yn wir, awgrymir hyn gan y ffurf yr argreffir y canlyniad ynddi gan y dehonglydd. Mae Ffigur 2.5 yn dangos cynrychioliad y strwythur hwn yn nhermau parau.
Ffigur 2.5: Y strwythur a ffurfir gan (cons (list 1 2) (list 3 4)).
Ffordd arall o feddwl am ddilyniannau y mae eu helfennau’n ddilyniannau yw fel coed. Elfennau’r dilyniant yw canghennau’r goeden, ac isgoed yw elfennau sydd eu hunain yn ddilyniannau. Mae Ffigur 2.6 yn dangos y strwythur yn Ffigur 2.5 wedi’i ystyried yn goeden.
Ffigur 2.6: Strwythur y rhestr yn Ffigur 2.5 wedi’i ystyried yn goeden.
Mae dychweliad yn offeryn naturiol ar gyfer ymdrin â strwythurau coed, gan y gallwn yn aml leihau gweithrediadau ar goed i weithrediadau ar eu canghennau, sydd yn eu tro yn lleihau i weithrediadau ar ganghennau’r canghennau, ac yn y blaen, nes inni gyrraedd dail y goeden. Fel enghraifft, cymharwch y weithdrefn length yn 2.2.1 â’r weithdrefn count-leaves, sy’n dychwelyd cyfanswm nifer dail coeden:
(define x (cons (list 1 2) (list 3 4)))
(length x)
3
(count-leaves x)
4
(list x x)
(((1 2) 3 4) ((1 2) 3 4))
(length (list x x))
2
(count-leaves (list x x))
8
I weithredu count-leaves, cofiwch y cynllun dychweliadol ar gyfer cyfrifo length:
Mae Length rhestr x yn 1 ynghyd ag lengthcdrx.
Mae Length y rhestr wag yn 0.
Mae Count-leaves yn debyg. Mae’r gwerth ar gyfer y rhestr wag yr un fath:
Mae Count-leaves y rhestr wag yn 0.
Ond yn y cam lleihau, lle tynnwn car y rhestr oddi arni, rhaid inni ystyried y gall yr car ei hun fod yn goeden y mae angen cyfrif ei dail. Felly, y cam lleihau priodol yw
Mae Count-leaves coeden x yn count-leavescarx ynghyd ag count-leavescdrx.
Yn olaf, drwy gymryd car dro ar ôl tro cyrhaeddwn ddail go iawn, felly mae angen achos sylfaenol arall:
Mae Count-leaves deilen yn 1.
I helpu i ysgrifennu gweithdrefnau dychweliadol ar goed, mae Scheme yn darparu’r traethiad cyntefig pair?, sy’n profi a yw ei arg yn bâr. Dyma’r weithdrefn gyflawn:79
Ymarfer 2.24: Tybiwch ein bod yn gwerthuso’r mynegiad (list 1 (list 2 (list 3 4))). Rhowch y canlyniad a argreffir gan y dehonglydd, y strwythur blychau a phwyntyddion cyfatebol, a’i ddehongliad fel coeden (fel yn Ffigur 2.6).
Ymarfer 2.25: Rhowch gyfuniadau o car ac cdr a fydd yn dewis 7 o bob un o’r rhestrau canlynol:
(1 3 (5 7) 9)
((7))
(1 (2 (3 (4 (5 (6 7))))))
Ymarfer 2.26: Tybiwch ein bod yn diffinio x ac y yn ddwy restr:
(define x (list 1 2 3))
(define y (list 4 5 6))
Pa ganlyniad a argreffir gan y dehonglydd wrth werthuso pob un o’r mynegiadau canlynol:
(append x y)
(cons x y)
(list x y)
Ymarfer 2.27: Addaswch eich gweithdrefn reverse o Ymarfer 2.18 i gynhyrchu gweithdrefn deep-reverse sy’n cymryd rhestr fel arg ac yn dychwelyd fel ei gwerth y rhestr â’i helfennau yn y drefn wrthdro, a phob isrestr hefyd wedi’i gwrthdroi ar bob lefel. Er enghraifft,
Ymarfer 2.28: Ysgrifennwch weithdrefn fringe sy’n cymryd coeden (wedi’i chynrychioli fel rhestr) fel arg ac yn dychwelyd rhestr y mae ei helfennau’n holl ddail y goeden wedi’u trefnu o’r chwith i’r dde. Er enghraifft,
Ymarfer 2.29: Mae symudyn deuaidd (binary mobile) yn cynnwys dwy gangen, cangen chwith a changen dde. Mae pob cangen yn wialen o hyd penodol, ac oddi arni mae naill ai pwysau neu symudyn deuaidd arall yn hongian. Gallwn gynrychioli symudyn deuaidd drwy ddefnyddio data cyfansawdd, gan ei adeiladu o ddwy gangen (er enghraifft, drwy ddefnyddio list):
(define (make-mobile left right)
(list left right))
Adeiladir cangen o length (y mae’n rhaid iddo fod yn rhif) ynghyd â structure, a all fod naill ai’n rhif (sy’n cynrychioli pwysau syml) neu’n symudyn arall:
Ysgrifennwch y detholwyr cyfatebol left-branch ac right-branch, sy’n dychwelyd canghennau symudyn, ac branch-length ac branch-structure, sy’n dychwelyd cydrannau cangen.
Gan ddefnyddio eich detholwyr, diffiniwch weithdrefn total-weight sy’n dychwelyd cyfanswm pwysau symudyn.
Dywedir bod symudyn mewn cydbwysedd os yw’r trorym a roddir gan ei gangen chwith uchaf yn hafal i’r un a roddir gan ei gangen dde uchaf (hynny yw, os yw hyd y wialen chwith wedi’i luosi â’r pwysau sy’n hongian oddi ar y wialen honno yn hafal i’r lluoswm cyfatebol ar yr ochr dde) ac os yw pob un o’r is-symudynnau sy’n hongian oddi ar ei ganghennau mewn cydbwysedd. Dyluniwch draethiad sy’n profi a yw symudyn deuaidd mewn cydbwysedd.
Tybiwch ein bod yn newid cynrychioliad symudynnau fel bod yr adeiladwyr yn
(define (make-mobile left right)
(cons left right))
(define (make-branch length structure)
(cons length structure))
Faint sydd angen i chi newid eich rhaglenni i drosi i’r cynrychioliad newydd?
Mapio dros goed
Yn union fel y mae map yn haniaeth rymus ar gyfer ymdrin â dilyniannau, mae map ynghyd â dychweliad yn haniaeth rymus ar gyfer ymdrin â choed. Er enghraifft, mae’r weithdrefn scale-tree, sy’n cyfateb i scale-list yn 2.2.1, yn cymryd fel argiau ffactor rhifiadol a choeden y mae ei dail yn rhifau. Mae’n dychwelyd coeden o’r un siâp, lle mae pob rhif wedi’i luosi â’r ffactor. Mae’r cynllun dychweliadol ar gyfer scale-tree yn debyg i’r un ar gyfer count-leaves:
Ffordd arall o weithredu scale-tree yw ystyried y goeden yn ddilyniant o isgoed a defnyddio map. Mapiwn dros y dilyniant, gan raddio pob isgoeden yn ei thro, a dychwelyd y rhestr o ganlyniadau. Yn yr achos sylfaenol, lle mae’r goeden yn ddeilen, lluoswn â’r ffactor yn syml:
Ymarfer 2.32: Gallwn gynrychioli set fel rhestr o elfennau gwahanol, a gallwn gynrychioli set holl is-setiau’r set fel rhestr o restrau. Er enghraifft, os mai (1 2 3) yw’r set, yna (() (3) (2) (2 3) (1) (1 3) (1 2) (1 2 3)) yw set yr holl is-setiau. Cwblhewch y diffiniad canlynol o weithdrefn sy’n cynhyrchu set is-setiau set, a rhowch esboniad clir o pam mae’n gweithio:
Wrth weithio â data cyfansawdd, pwysleisiwyd sut mae haniaethu data yn caniatáu inni ddylunio rhaglenni heb fynd yn sownd ym manylion cynrychioliadau data, a sut mae haniaethu’n cadw’r hyblygrwydd inni arbrofi â chynrychioliadau amgen. Yn yr adran hon, cyflwynwn egwyddor ddylunio rymus arall ar gyfer gweithio â strwythurau data—defnyddio rhyngwynebau confensiynol.
Yn 1.3 gwelsom sut y gall haniaethau rhaglen, wedi’u gweithredu fel gweithdrefnau trefn uwch, ddal patrymau cyffredin mewn rhaglenni sy’n ymdrin â data rhifiadol. Mae ein gallu i lunio gweithrediadau cyfatebol ar gyfer gweithio â data cyfansawdd yn dibynnu’n hanfodol ar yr arddull a ddefnyddiwn i drin ein strwythurau data. Ystyriwch, er enghraifft, y weithdrefn ganlynol, sy’n cyfateb i’r weithdrefn count-leaves yn 2.2.2, sy’n cymryd coeden fel arg ac yn cyfrifo swm sgwariau’r dail sy’n odrifau:
Ar yr wyneb, mae’r weithdrefn hon yn wahanol iawn i’r un ganlynol, sy’n adeiladu rhestr o’r holl rifau Fibonacci eilrif , lle mae yn llai na neu’n hafal i gyfanrif penodol :
(define (even-fibs n)
(define (next k)
(if (> k n)
nil
(let ((f (fib k)))
(if (even? f)
(cons f (next (+ k 1)))
(next (+ k 1))))))
(next 0))
Er bod y ddwy weithdrefn hyn yn wahanol iawn o ran strwythur, mae disgrifiad mwy haniaethol o’r ddau gyfrifiad yn datgelu llawer iawn o debygrwydd. Mae’r rhaglen gyntaf yn
rhestru dail coeden;
eu hidlo, gan ddethol yr odrifau;
sgwario pob un o’r rhai a ddetholwyd; ac yn
cronni’r canlyniadau drwy ddefnyddio +, gan ddechrau gyda 0.
Mae’r ail raglen yn
rhestru’r cyfanrifau o 0 i ;
cyfrifo’r rhif Fibonacci ar gyfer pob cyfanrif;
eu hidlo, gan ddethol yr eilrifau; ac yn
cronni’r canlyniadau drwy ddefnyddio cons, gan ddechrau gyda’r rhestr wag.
Byddai peiriannydd prosesu signalau yn ei chael yn naturiol gysyniadoli’r prosesau hyn yn nhermau signalau sy’n llifo drwy raeadr o gamau, pob un yn gweithredu rhan o gynllun y rhaglen, fel y dangosir yn Ffigur 2.7. Yn sum-odd-squares, dechreuwn â rhestrydd, sy’n cynhyrchu “signal” sy’n cynnwys dail coeden benodol. Pasir y signal hwn drwy hidlydd, sy’n dileu pob elfen heblaw’r odrifau. Pasir y signal canlyniadol yn ei dro drwy fapiad, sef “trawsddygiadur” sy’n cymhwyso’r weithdrefn square i bob elfen. Yna bwydir allbwn y mapiad i gronnwr, sy’n cyfuno’r elfennau drwy ddefnyddio +, gan ddechrau o 0 cychwynnol. Mae’r cynllun ar gyfer even-fibs yn gyfatebol.
Ffigur 2.7: Mae cynlluniau llif signalau’r gweithdrefnau sum-odd-squares (uchod) ac even-fibs (isod) yn datgelu’r hyn sy’n gyffredin i’r ddwy raglen.
Yn anffodus, nid yw’r ddau ddiffiniad gweithdrefn uchod yn dangos y strwythur llif signalau hwn. Er enghraifft, os archwiliwn y weithdrefn sum-odd-squares, gwelwn fod y rhestru’n cael ei weithredu’n rhannol gan y profion null? ac pair? ac yn rhannol gan strwythur dychweliadol coediog y weithdrefn. Yn yr un modd, ceir y cronni’n rhannol yn y profion ac yn rhannol yn yr adio a ddefnyddir yn y dychweliad. Yn gyffredinol, nid oes rhannau penodol o’r naill weithdrefn na’r llall sy’n cyfateb i’r elfennau yn y disgrifiad llif signalau. Mae ein dwy weithdrefn yn dadelfennu’r cyfrifiadau mewn ffordd wahanol, gan wasgaru’r rhestru dros y rhaglen a’i gymysgu â’r mapio, yr hidlo, a’r cronni. Pe gallem drefnu ein rhaglenni i wneud y strwythur llif signalau yn amlwg yn y gweithdrefnau a ysgrifennwn, byddai hyn yn cynyddu eglurder cysyniadol y cod canlyniadol.
Gweithrediadau Dilyniant
Yr allwedd i drefnu rhaglenni fel eu bod yn adlewyrchu’r strwythur llif signalau yn gliriach yw canolbwyntio ar y “signalau” sy’n llifo o un cam yn y broses i’r nesaf. Os cynrychiolwn y signalau hyn fel rhestrau, gallwn ddefnyddio gweithrediadau rhestr i weithredu’r prosesu ym mhob un o’r camau. Er enghraifft, gallwn weithredu camau mapio’r diagramau llif signalau drwy ddefnyddio’r weithdrefn map o 2.2.1:
(map square (list 1 2 3 4 5))
(1 4 9 16 25)
Cyflawnir hidlo dilyniant i ddethol dim ond yr elfennau hynny sy’n bodloni traethiad penodol drwy
Y cyfan sy’n weddill i weithredu diagramau llif signalau yw rhestru’r dilyniant o elfennau i’w prosesu. Ar gyfer even-fibs, mae angen cynhyrchu’r dilyniant o gyfanrifau mewn ystod benodol, a gallwn wneud hynny fel a ganlyn:
Gallwn yn awr ail-lunio sum-odd-squares ac even-fibs fel yn y diagramau llif signalau. Ar gyfer sum-odd-squares, rhestrwn ddilyniant dail y goeden, hidlwn hwn i gadw’r odrifau yn y dilyniant yn unig, sgwariwn bob elfen, a symiwn y canlyniadau:
Ar gyfer even-fibs, rhestrwn y cyfanrifau o 0 i , cynhyrchwn y rhif Fibonacci ar gyfer pob un o’r cyfanrifau hyn, hidlwn y dilyniant canlyniadol i gadw’r elfennau eilrif yn unig, a chronnwn y canlyniadau mewn rhestr:
Gwerth mynegi rhaglenni fel gweithrediadau dilyniant yw bod hyn yn ein helpu i greu dyluniadau rhaglen modiwlar, hynny yw, dyluniadau a adeiladir drwy gyfuno darnau sy’n gymharol annibynnol. Gallwn annog dylunio modiwlar drwy ddarparu llyfrgell o gydrannau safonol ynghyd â rhyngwyneb confensiynol ar gyfer cysylltu’r cydrannau mewn ffyrdd hyblyg.
Mae adeiladu modiwlar yn strategaeth rymus ar gyfer rheoli cymhlethdod mewn dylunio peirianyddol. Mewn cymwysiadau prosesu signalau go iawn, er enghraifft, mae dylunwyr yn adeiladu systemau’n rheolaidd drwy gysylltu mewn rhaeadr elfennau a ddewiswyd o deuluoedd safonedig o hidlyddion a thrawsddygiaduron. Yn yr un modd, mae gweithrediadau dilyniant yn darparu llyfrgell o elfennau rhaglen safonol y gallwn eu cyfuno mewn amryw ffyrdd. Er enghraifft, gallwn ailddefnyddio darnau o’r gweithdrefnau sum-odd-squares ac even-fibs mewn rhaglen sy’n adeiladu rhestr o sgwariau’r rhif Fibonacci cyntaf:
Gallwn hefyd lunio cymwysiadau prosesu data confensiynol yn nhermau gweithrediadau dilyniant. Tybiwch fod gennym ddilyniant o gofnodion personél a’n bod eisiau canfod cyflog y rhaglennydd sy’n ennill fwyaf. Tybiwch fod gennym ddetholwr salary sy’n dychwelyd cyflog cofnod, a thraethiad programmer? sy’n profi a yw cofnod yn perthyn i raglennydd. Yna gallwn ysgrifennu
Dim ond awgrym o’r ystod enfawr o weithrediadau y gellir eu mynegi fel gweithrediadau dilyniant a roddir gan yr enghreifftiau hyn.81
Mae dilyniannau, a weithredir yma fel rhestrau, yn gwasanaethu fel rhyngwyneb confensiynol sy’n caniatáu inni gyfuno modiwlau prosesu. Yn ogystal, pan gynrychiolwn strwythurau’n unffurf fel dilyniannau, rydym wedi lleoli’r dibyniaethau ar strwythurau data yn ein rhaglenni mewn nifer bach o weithrediadau dilyniant. Drwy newid y rhain, gallwn arbrofi â chynrychioliadau amgen o ddilyniannau, gan adael dyluniad cyffredinol ein rhaglenni yn gyfan. Defnyddiwn y gallu hwn yn 3.5, pan gyffredinolwn y patrwm prosesu dilyniannau i gynnwys dilyniannau anfeidrol.
Ymarfer 2.33: Llenwch y mynegiadau coll i gwblhau’r diffiniadau canlynol o rai gweithrediadau sylfaenol ar gyfer trin rhestrau fel gweithrediadau cronni:
Ymarfer 2.34: Gellir ffurfio gwerthuso polynomial mewn ar werth penodol o fel proses gronni. Gwerthuswn y polynomial drwy ddefnyddio algorithm adnabyddus o’r enw rheol Horner, sy’n strwythuro’r cyfrifiad fel Mewn geiriau eraill, dechreuwn ag , lluoswn ag , ychwanegwn , lluoswn ag , ac yn y blaen, nes cyrraedd .82
Llenwch y templed canlynol i gynhyrchu gweithdrefn sy’n gwerthuso polynomial drwy ddefnyddio rheol Horner. Tybiwch fod cyfernodau’r polynomial wedi’u trefnu mewn dilyniant, o hyd at .
Ymarfer 2.36: Mae’r weithdrefn accumulate-n yn debyg i accumulate, heblaw ei bod yn cymryd fel ei thrydydd arg ddilyniant o ddilyniannau, y tybir bod ganddynt oll yr un nifer o elfennau. Mae’n cymhwyso’r weithdrefn gronni ddynodedig i gyfuno holl elfennau cyntaf y dilyniannau, holl ail elfennau’r dilyniannau, ac yn y blaen, ac yn dychwelyd dilyniant o’r canlyniadau. Er enghraifft, os yw s yn ddilyniant sy’n cynnwys pedwar dilyniant, ((1 2 3) (4 5 6) (7 8 9) (10 11
12)), yna dylai gwerth (accumulate-n + 0 s) fod yn ddilyniant (22 26 30). Llenwch y mynegiadau coll yn y diffiniad canlynol o accumulate-n:
(define (accumulate-n op init seqs)
(if (null? (car seqs))
nil
(cons (accumulate op init ⟨??⟩)
(accumulate-n op init ⟨??⟩))))
Ymarfer 2.37: Tybiwch ein bod yn cynrychioli fectorau v = fel dilyniannau o rifau, a matricsau m = fel dilyniannau o fectorau (rhesi’r matrics). Er enghraifft, cynrychiolir y matrics fel y dilyniant ((1 2 3 4) (4 5 6 6) (6 7 8 9)). Gyda’r cynrychioliad hwn, gallwn ddefnyddio gweithrediadau dilyniant i fynegi’n gryno y gweithrediadau matrics a fector sylfaenol. Dyma’r gweithrediadau hyn (a ddisgrifir mewn unrhyw lyfr ar algebra matricsau): Gallwn ddiffinio’r lluoswm dot fel83
(define (dot-product v w)
(accumulate + 0 (map * v w)))
Llenwch y mynegiadau coll yn y gweithdrefnau canlynol ar gyfer cyfrifo’r gweithrediadau matrics eraill. (Diffinnir y weithdrefn accumulate-n yn Ymarfer 2.36.)
Ymarfer 2.38: Gelwir y weithdrefn accumulate hefyd yn fold-right, oherwydd ei bod yn cyfuno elfen gyntaf y dilyniant â chanlyniad cyfuno’r holl elfennau i’r dde. Mae hefyd fold-left, sy’n debyg i fold-right, heblaw ei bod yn cyfuno elfennau gan weithio i’r cyfeiriad arall:
(define (fold-left op initial sequence)
(define (iter result rest)
(if (null? rest)
result
(iter (op result (car rest))
(cdr rest))))
(iter initial sequence))
Gallwn ehangu’r patrwm dilyniannau i gynnwys llawer o gyfrifiadau a fynegir yn gyffredin drwy ddefnyddio dolenni nythol.84 Ystyriwch y broblem hon: O gael cyfanrif positif , canfyddwch bob pâr trefnedig o gyfanrifau positif gwahanol ac , lle , fel bod yn gysefin. Er enghraifft, os yw yn 6, yna dyma’r parau: Ffordd naturiol o drefnu’r cyfrifiad hwn yw cynhyrchu’r dilyniant o bob pâr trefnedig o gyfanrifau positif sy’n llai na neu’n hafal i , hidlo i ddethol y parau hynny y mae eu swm yn gysefin, ac yna, ar gyfer pob pâr sy’n pasio drwy’r hidlydd, cynhyrchu’r tripled .
Dyma ffordd o gynhyrchu’r dilyniant o barau: Ar gyfer pob cyfanrif , rhestrwch y cyfanrifau , ac ar gyfer pob ac o’r fath cynhyrchwch y pâr . Yn nhermau gweithrediadau dilyniant, mapiwn ar hyd y dilyniant (enumerate-interval 1 n). Ar gyfer pob yn y dilyniant hwn, mapiwn ar hyd y dilyniant (enumerate-interval 1 (- i 1)). Ar gyfer pob yn y dilyniant olaf hwn, cynhyrchwn y pâr (list i j). Mae hyn yn rhoi dilyniant o barau inni ar gyfer pob . Mae cyfuno’r holl ddilyniannau ar gyfer pob (drwy gronni ag append) yn cynhyrchu’r dilyniant gofynnol o barau:85
(accumulate
append
nil
(map (lambda (i)
(map (lambda (j)
(list i j))
(enumerate-interval 1 (- i 1))))
(enumerate-interval 1 n)))
Mae’r cyfuniad o fapio a chronni ag append mor gyffredin yn y math hwn o raglen fel y byddwn yn ei ynysu fel gweithdrefn ar wahân:
Nawr hidlwch y dilyniant hwn o barau i ganfod y rhai y mae eu swm yn gysefin. Gelwir y traethiad hidlo ar gyfer pob elfen yn y dilyniant; pâr yw ei arg a rhaid iddo echdynnu’r cyfanrifau o’r pâr. Felly, y traethiad i’w gymhwyso i bob elfen yn y dilyniant yw
Yn olaf, cynhyrchwch y dilyniant o ganlyniadau drwy fapio dros y parau a hidlwyd gan ddefnyddio’r weithdrefn ganlynol, sy’n adeiladu tripled sy’n cynnwys dwy elfen y pâr ynghyd â’u swm:
Mae mapiadau nythol hefyd yn ddefnyddiol ar gyfer dilyniannau heblaw’r rhai sy’n rhestru cyfyngau. Tybiwch ein bod yn dymuno cynhyrchu holl drynewidiadau set , hynny yw, yr holl ffyrdd o drefnu eitemau’r set. Er enghraifft, trynewidiadau yw , , , , , ac . Dyma gynllun ar gyfer cynhyrchu trynewidiadau : Ar gyfer pob eitem yn , cynhyrchwch yn ddychweliadol y dilyniant o drynewidiadau ,86 ac ychwanegwch at flaen pob un. Mae hyn yn rhoi, ar gyfer pob yn , y dilyniant o drynewidiadau sy’n dechrau ag . Mae cyfuno’r dilyniannau hyn ar gyfer pob yn rhoi holl drynewidiadau :87
(define (permutations s)
(if (null? s) ; empty set?
(list nil) ; sequence containing empty set
(flatmap (lambda (x)
(map (lambda (p)
(cons x p))
(permutations
(remove x s))))
s)))
Sylwch sut mae’r strategaeth hon yn lleihau’r broblem o gynhyrchu trynewidiadau i’r broblem o gynhyrchu trynewidiadau setiau sydd â llai o elfennau nag . Yn yr achos terfynol, gweithiwn ein ffordd i lawr at y rhestr wag, sy’n cynrychioli set heb elfennau. Ar gyfer hon, cynhyrchwn (list
nil), sef dilyniant ag un eitem, sef y set heb elfennau. Mae’r weithdrefn remove a ddefnyddir yn permutations yn dychwelyd yr holl eitemau mewn dilyniant penodol heblaw am eitem benodol. Gellir mynegi hyn fel hidlydd syml:
Ymarfer 2.40: Diffiniwch weithdrefn unique-pairs sydd, o gael cyfanrif , yn cynhyrchu’r dilyniant o barau gyda . Defnyddiwch unique-pairs i symleiddio’r diffiniad o prime-sum-pairs a roddwyd uchod.
Ymarfer 2.41: Ysgrifennwch weithdrefn i ganfod pob tripled trefnedig o gyfanrifau positif gwahanol , , ac sy’n llai na neu’n hafal i gyfanrif penodol ac y mae eu swm yn gyfanrif penodol .
Ymarfer 2.42: Mae “pos yr wyth brenhines” yn gofyn sut i osod wyth brenhines ar fwrdd gwyddbwyll fel nad yw unrhyw frenhines dan fygythiad gan unrhyw un arall (h.y., nid oes dwy frenhines yn yr un rhes, colofn, na chroeslin). Dangosir un datrysiad posibl yn Ffigur 2.8. Un ffordd o ddatrys y pos yw gweithio ar draws y bwrdd, gan osod brenhines ym mhob colofn. Ar ôl inni osod brenhines, rhaid gosod brenhines mewn safle lle nad yw’n bygwth unrhyw un o’r breninesau sydd eisoes ar y bwrdd. Gallwn lunio’r dull hwn yn ddychweliadol: Tybiwch ein bod eisoes wedi cynhyrchu’r dilyniant o’r holl ffyrdd posibl o osod brenhines yn colofn gyntaf y bwrdd. Ar gyfer pob un o’r ffyrdd hyn, cynhyrchwch set estynedig o safleoedd drwy osod brenhines ym mhob rhes o golofn . Nawr hidlwch y rhain, gan gadw’r safleoedd hynny yn unig lle mae’r frenhines yng ngholofn yn ddiogel mewn perthynas â’r breninesau eraill. Mae hyn yn cynhyrchu’r dilyniant o’r holl ffyrdd o osod brenhines yn colofn gyntaf y bwrdd. Drwy barhau â’r broses hon, cynhyrchwn nid un datrysiad yn unig, ond holl ddatrysiadau’r pos.
Ffigur 2.8: Datrysiad i bos yr wyth brenhines.
Gweithredwn y datrysiad hwn fel gweithdrefn queens, sy’n dychwelyd dilyniant o’r holl ddatrysiadau i’r broblem o osod brenhines ar fwrdd gwyddbwyll . Mae gan Queens weithdrefn fewnol queen-cols sy’n dychwelyd y dilyniant o’r holl ffyrdd o osod breninesau yn colofn gyntaf y bwrdd.
(define (queens board-size)
(define (queen-cols k)
(if (= k 0)
(list empty-board)
(filter
(lambda (positions)
(safe? k positions))
(flatmap
(lambda (rest-of-queens)
(map (lambda (new-row)
(adjoin-position
new-row
k
rest-of-queens))
(enumerate-interval
1
board-size)))
(queen-cols (- k 1))))))
(queen-cols board-size))
Yn y weithdrefn hon mae rest-of-queens yn ffordd o osod brenhines yn y colofn gyntaf, ac mae new-row yn rhes arfaethedig ar gyfer gosod brenhines colofn . Cwblhewch y rhaglen drwy weithredu’r cynrychioliad ar gyfer setiau o safleoedd ar y bwrdd, gan gynnwys y weithdrefn adjoin-position, sy’n ychwanegu safle rhes-colofn newydd at set o safleoedd, ac empty-board, sy’n cynrychioli set wag o safleoedd. Rhaid i chi hefyd ysgrifennu’r weithdrefn safe?, sy’n penderfynu, ar gyfer set o safleoedd, a yw’r frenhines yng ngholofn yn ddiogel mewn perthynas â’r lleill. (Sylwch nad oes angen ond gwirio a yw’r frenhines newydd yn ddiogel—mae diogelwch y breninesau eraill mewn perthynas â’i gilydd eisoes wedi’i warantu.)
Ymarfer 2.43: Mae Louis Reasoner yn cael amser ofnadwy wrth wneud Ymarfer 2.42. Mae ei weithdrefn queens i’w gweld yn gweithio, ond mae’n rhedeg yn eithriadol o araf. (Nid yw Louis byth yn llwyddo i aros yn ddigon hir iddi ddatrys hyd yn oed yr achos .) Pan ofynna Louis i Eva Lu Ator am help, mae hi’n tynnu sylw at y ffaith ei fod wedi cyfnewid trefn y mapiadau nythol yn yr flatmap, gan ei ysgrifennu fel
(flatmap
(lambda (new-row)
(map (lambda (rest-of-queens)
(adjoin-position
new-row k rest-of-queens))
(queen-cols (- k 1))))
(enumerate-interval 1 board-size))
Esboniwch pam mae’r cyfnewid hwn yn gwneud i’r rhaglen redeg yn araf. Amcangyfrifwch pa mor hir y bydd rhaglen Louis yn ei gymryd i ddatrys pos yr wyth brenhines, gan dybio bod y rhaglen yn Ymarfer 2.42 yn datrys y pos mewn amser .
2.2.4Enghraifft: Iaith Darluniau
Mae’r adran hon yn cyflwyno iaith syml ar gyfer llunio darluniau sy’n dangos grym haniaethu data a’r briodwedd cau, ac sydd hefyd yn defnyddio gweithdrefnau trefn uwch mewn ffordd hanfodol. Dyluniwyd yr iaith i’w gwneud yn hawdd arbrofi â phatrymau megis y rhai yn Ffigur 2.9, sy’n cynnwys elfennau ailadroddus a symudir ac a raddir.88 Yn yr iaith hon, cynrychiolir y gwrthrychau data a gyfunir fel gweithdrefnau yn hytrach nag fel strwythur rhestr. Yn union fel yr oedd cons, sy’n bodloni’r briodwedd cau, yn caniatáu inni adeiladu strwythur rhestr o gymhlethdod mympwyol yn hawdd, mae’r gweithrediadau yn yr iaith hon, sydd hefyd yn bodloni’r briodwedd cau, yn caniatáu inni adeiladu patrymau o gymhlethdod mympwyol yn hawdd.
Ffigur 2.9: Dyluniadau a gynhyrchwyd â’r iaith darluniau.
Yr iaith darluniau
Pan ddechreuasom astudio rhaglennu yn 1.1, pwysleisiasom bwysigrwydd disgrifio iaith drwy ganolbwyntio ar ei helfennau cyntefig, ei moddion cyfuno, a’i moddion haniaethu. Dilynwn y fframwaith hwnnw yma.
Rhan o geinder yr iaith darluniau hon yw mai dim ond un math o elfen sydd, a elwir yn beintiwr. Mae peintiwr yn llunio delwedd a symudir ac a raddir i ffitio o fewn ffrâm benodedig ar ffurf paralelogram. Er enghraifft, mae peintiwr cyntefig y byddwn yn ei alw’n wave sy’n gwneud llun llinell bras, fel y dangosir yn Ffigur 2.10. Mae gwir siâp y llun yn dibynnu ar y ffrâm—cynhyrchir y pedair delwedd yn ffigur 2.10 gan yr un peintiwr wave, ond mewn perthynas â phedair ffrâm wahanol. Gall peintwyr fod yn fwy cywrain na hyn: Mae’r peintiwr cyntefig o’r enw rogers yn peintio darlun o sylfaenydd MIT, William Barton Rogers, fel y dangosir yn Ffigur 2.11.89 Llunnir y pedair delwedd yn ffigur 2.11 mewn perthynas â’r un pedair ffrâm â’r delweddau wave yn ffigur 2.10.
Ffigur 2.10: Delweddau a gynhyrchwyd gan y peintiwr wave, mewn perthynas â phedair ffrâm wahanol. Nid yw’r fframiau, a ddangosir â llinellau dotiog, yn rhan o’r delweddau.
Ffigur 2.11: Delweddau o William Barton Rogers, sylfaenydd ac arlywydd cyntaf MIT, wedi’u peintio mewn perthynas â’r un pedair ffrâm ag yn Ffigur 2.10 (y ddelwedd wreiddiol o Wikimedia Commons).
I gyfuno delweddau, defnyddiwn amrywiol weithrediadau sy’n adeiladu peintwyr newydd o beintwyr penodol. Er enghraifft, mae’r gweithrediad beside yn cymryd dau beintiwr ac yn cynhyrchu peintiwr cyfansawdd newydd sy’n llunio delwedd y peintiwr cyntaf yn hanner chwith y ffrâm a delwedd yr ail beintiwr yn hanner dde’r ffrâm. Yn yr un modd, mae below yn cymryd dau beintiwr ac yn cynhyrchu peintiwr cyfansawdd sy’n llunio delwedd y peintiwr cyntaf islaw delwedd yr ail beintiwr. Mae rhai gweithrediadau’n trawsffurfio un peintiwr i gynhyrchu peintiwr newydd. Er enghraifft, mae flip-vert yn cymryd peintiwr ac yn cynhyrchu peintiwr sy’n llunio ei ddelwedd wyneb i waered, ac mae flip-horiz yn cynhyrchu peintiwr sy’n llunio delwedd y peintiwr gwreiddiol gyda’r chwith a’r dde wedi’u gwrthdroi.
Mae Ffigur 2.12 yn dangos llun peintiwr o’r enw wave4 a adeiladir mewn dau gam gan ddechrau ag wave:
Ffigur 2.12: Creu ffigur cymhleth, gan ddechrau â pheintiwr waveFfigur 2.10.
Wrth adeiladu delwedd gymhleth fel hyn rydym yn defnyddio’r ffaith bod peintwyr yn gaeedig o dan foddion cyfuno’r iaith. Mae beside neu below dau beintiwr ei hun yn beintiwr; felly, gallwn ei ddefnyddio fel elfen wrth wneud peintwyr mwy cymhleth. Fel wrth adeiladu strwythur rhestr drwy ddefnyddio cons, mae priodwedd cau ein data o dan y moddion cyfuno yn hanfodol i’r gallu i greu strwythurau cymhleth gan ddefnyddio ychydig o weithrediadau yn unig.
Unwaith y gallwn gyfuno peintwyr, hoffem allu haniaethu patrymau nodweddiadol o gyfuno peintwyr. Byddwn yn gweithredu gweithrediadau’r peintwyr fel gweithdrefnau Scheme. Mae hyn yn golygu nad oes angen mecanwaith haniaethu arbennig arnom yn yr iaith darluniau: Gan mai gweithdrefnau Scheme cyffredin yw’r moddion cyfuno, mae gennym yn awtomatig y gallu i wneud unrhyw beth â gweithrediadau peintwyr y gallwn ei wneud â gweithdrefnau. Er enghraifft, gallwn haniaethu’r patrwm yn wave4 fel
Gallwn hefyd ddiffinio gweithrediadau dychweliadol. Dyma un sy’n gwneud i beintwyr ymrannu a changhennu i’r dde fel y dangosir yn Ffigur 2.13 a Ffigur 2.14:
Ffigur 2.14: Y gweithrediadau dychweliadol right-split ac corner-split wedi’u cymhwyso i’r peintwyr wave ac rogers. Mae cyfuno pedwar ffigur corner-split yn cynhyrchu dyluniadau square-limit cymesur fel y dangosir yn Ffigur 2.9.
Drwy osod pedwar copi o corner-split yn briodol, cawn batrwm o’r enw square-limit, y dangosir ei gymhwysiad i wave ac rogers yn Ffigur 2.9:
Ymarfer 2.44: Diffiniwch y weithdrefn up-split a ddefnyddir gan corner-split. Mae’n debyg i right-split, heblaw ei bod yn cyfnewid rolau below ac beside.
Gweithrediadau trefn uwch
Yn ogystal â haniaethu patrymau o gyfuno peintwyr, gallwn weithio ar lefel uwch, gan haniaethu patrymau o gyfuno gweithrediadau peintwyr. Hynny yw, gallwn ystyried gweithrediadau’r peintwyr yn elfennau i’w trin, a gallwn ysgrifennu moddion cyfuno ar gyfer yr elfennau hyn—gweithdrefnau sy’n cymryd gweithrediadau peintwyr fel argiau ac yn creu gweithrediadau peintwyr newydd.
Er enghraifft, mae flipped-pairs ac square-limit ill dau yn trefnu pedwar copi o ddelwedd peintiwr mewn patrwm sgwâr; dim ond yn y ffordd y maent yn cyfeirio’r copïau y maent yn gwahaniaethu. Un ffordd o haniaethu’r patrwm hwn o gyfuno peintwyr yw drwy’r weithdrefn ganlynol, sy’n cymryd pedwar gweithrediad peintiwr un arg ac yn cynhyrchu gweithrediad peintiwr sy’n trawsffurfio peintiwr penodol â’r pedwar gweithrediad hynny ac yn trefnu’r canlyniadau mewn sgwâr. Tl, tr, bl, ac br yw’r trawsffurfiadau i’w cymhwyso i’r copi chwith uchaf, y copi dde uchaf, y copi chwith isaf, a’r copi dde isaf, yn y drefn honno.
Ymarfer 2.45: Gellir mynegi Right-split ac up-split fel enghreifftiau o weithrediad rhannu cyffredinol. Diffiniwch weithdrefn split sydd â’r briodwedd bod gwerthuso
yn cynhyrchu gweithdrefnau right-split ac up-split sydd â’r un ymddygiad â’r rhai a ddiffiniwyd eisoes.
Fframiau
Cyn y gallwn ddangos sut i weithredu peintwyr a’u moddion cyfuno, rhaid inni ystyried fframiau yn gyntaf. Gellir disgrifio ffrâm gan dri fector—fector tarddbwynt a dau fector ymyl. Mae’r fector tarddbwynt yn pennu dadleoliad tarddbwynt y ffrâm o ryw darddbwynt absoliwt yn y plân, ac mae’r fectorau ymyl yn pennu dadleoliadau corneli’r ffrâm o’i tharddbwynt. Os yw’r ymylon yn berpendicwlar, bydd y ffrâm yn betryalog. Fel arall, bydd y ffrâm yn baralelogram mwy cyffredinol.
Mae Ffigur 2.15 yn dangos ffrâm a’i fectorau cysylltiedig. Yn unol â haniaethu data, nid oes angen inni fod yn benodol eto ynghylch sut y cynrychiolir fframiau, heblaw dweud bod adeiladydd make-frame, sy’n cymryd tri fector ac yn cynhyrchu ffrâm, a thri detholwr cyfatebol origin-frame, edge1-frame, ac edge2-frame (gweler Ymarfer 2.47).
Ffigur 2.15: Disgrifir ffrâm gan dri fector — tarddbwynt a dau ymyl.
Byddwn yn defnyddio cyfesurynnau yn y sgwâr uned i bennu delweddau. Gyda phob ffrâm, cysylltwn fapiad cyfesurynnau’r ffrâm, a ddefnyddir i symud a graddio delweddau i ffitio’r ffrâm. Mae’r mapiad yn trawsffurfio’r sgwâr uned yn ffrâm drwy fapio’r fector i’r swm fectorau Er enghraifft, mapir (0, 0) i darddbwynt y ffrâm, (1, 1) i’r fertig sydd gyferbyn â’r tarddbwynt ar y groeslin, a (0.5, 0.5) i ganol y ffrâm. Gallwn greu mapiad cyfesurynnau ffrâm â’r weithdrefn ganlynol:92
Sylwch fod cymhwyso frame-coord-map i ffrâm yn dychwelyd gweithdrefn sydd, o gael fector, yn dychwelyd fector. Os yw’r fector arg yn y sgwâr uned, bydd y fector canlyniadol yn y ffrâm. Er enghraifft, mae
((frame-coord-map a-frame) (make-vect 0 0))
yn dychwelyd yr un fector â
(origin-frame a-frame)
Ymarfer 2.46: Gellir cynrychioli fector dau ddimensiwn sy’n mynd o’r tarddbwynt at bwynt fel pâr sy’n cynnwys cyfesuryn a chyfesuryn . Gweithredwch haniaeth data ar gyfer fectorau drwy roi adeiladydd make-vect a detholwyr cyfatebol xcor-vect ac ycor-vect. Yn nhermau eich detholwyr a’ch adeiladydd, gweithredwch weithdrefnau add-vect, sub-vect, ac scale-vect sy’n cyflawni’r gweithrediadau adio fectorau, tynnu fectorau, a lluosi fector â sgalar:
Ymarfer 2.47: Dyma ddau adeiladydd posibl ar gyfer fframiau:
Ar gyfer pob adeiladydd, darparwch y detholwyr priodol i gynhyrchu gweithrediad ar gyfer fframiau.
Peintwyr
Cynrychiolir peintiwr fel gweithdrefn sydd, o gael ffrâm fel arg, yn llunio delwedd benodol wedi’i symud a’i graddio i ffitio’r ffrâm. Hynny yw, os yw p yn beintiwr ac f yn ffrâm, yna cynhyrchwn ddelwedd p yn f drwy alw p ag f fel arg.
Mae manylion gweithredu peintwyr cyntefig yn dibynnu ar nodweddion penodol y system graffeg a’r math o ddelwedd i’w llunio. Er enghraifft, tybiwch fod gennym weithdrefn draw-line sy’n llunio llinell ar y sgrin rhwng dau bwynt penodedig. Yna gallwn greu peintwyr ar gyfer lluniadau llinell, megis y peintiwr wave yn Ffigur 2.10, o restrau o segmentau llinell fel a ganlyn:93
Rhoddir y segmentau drwy ddefnyddio cyfesurynnau mewn perthynas â’r sgwâr uned. Ar gyfer pob segment yn y rhestr, mae’r peintiwr yn trawsffurfio pwyntiau terfyn y segment â mapiad cyfesurynnau’r ffrâm ac yn llunio llinell rhwng y pwyntiau a drawsffurfiwyd.
Mae cynrychioli peintwyr fel gweithdrefnau yn codi rhwystr haniaethu grymus yn yr iaith darluniau. Gallwn greu a chymysgu pob math o beintwyr cyntefig, wedi’u seilio ar amrywiaeth o alluoedd graffeg. Nid yw manylion eu gweithrediad yn bwysig. Gall unrhyw weithdrefn wasanaethu fel peintiwr, ar yr amod ei bod yn cymryd ffrâm fel arg ac yn llunio rhywbeth wedi’i raddio i ffitio’r ffrâm.94
Ymarfer 2.48: Gellir cynrychioli segment llinell cyfeiriedig yn y plân fel pâr o fectorau—y fector sy’n mynd o’r tarddbwynt at bwynt dechrau’r segment, a’r fector sy’n mynd o’r tarddbwynt at bwynt gorffen y segment. Defnyddiwch eich cynrychioliad fectorau o Ymarfer 2.46 i ddiffinio cynrychioliad ar gyfer segmentau ag adeiladydd make-segment a detholwyr start-segment ac end-segment.
Ymarfer 2.49: Defnyddiwch segments->painter i ddiffinio’r peintwyr cyntefig canlynol:
Y peintiwr sy’n llunio amlinell y ffrâm benodedig.
Y peintiwr sy’n llunio “X” drwy gysylltu corneli cyferbyn y ffrâm.
Y peintiwr sy’n llunio siâp diemwnt drwy gysylltu canolbwyntiau ochrau’r ffrâm.
Y peintiwr wave.
Trawsffurfio a chyfuno peintwyr
Mae gweithrediad ar beintwyr (megis flip-vert neu beside) yn gweithio drwy greu peintiwr sy’n galw’r peintwyr gwreiddiol mewn perthynas â fframiau a ddeillir o’r ffrâm arg. Felly, er enghraifft, nid oes rhaid i flip-vert wybod sut mae peintiwr yn gweithio er mwyn ei droi wyneb i waered—dim ond gwybod sut i droi ffrâm wyneb i waered sydd ei angen: Mae’r peintiwr a drowyd yn defnyddio’r peintiwr gwreiddiol, ond yn y ffrâm wrthdro.
Mae gweithrediadau peintwyr wedi’u seilio ar y weithdrefn transform-painter, sy’n cymryd peintiwr a gwybodaeth am sut i drawsffurfio ffrâm fel argiau ac yn cynhyrchu peintiwr newydd. Pan elwir y peintiwr a drawsffurfiwyd ar ffrâm, mae’n trawsffurfio’r ffrâm ac yn galw’r peintiwr gwreiddiol ar y ffrâm a drawsffurfiwyd. Pwyntiau (wedi’u cynrychioli fel fectorau) yw’r argiau i transform-painter, ac maent yn pennu corneli’r ffrâm newydd: Pan gânt eu mapio i’r ffrâm, mae’r pwynt cyntaf yn pennu tarddbwynt y ffrâm newydd ac mae’r ddau arall yn pennu pennau ei fectorau ymyl. Felly, mae argiau o fewn y sgwâr uned yn pennu ffrâm sydd o fewn y ffrâm wreiddiol.
Dyma sut i droi delweddau peintwyr wyneb i waered yn fertigol:
(define (flip-vert painter)
(transform-painter
painter
(make-vect 0.0 1.0) ; new origin
(make-vect 1.0 1.0) ; new end of edge1
(make-vect 0.0 0.0))) ; new end of edge2
Drwy ddefnyddio transform-painter, gallwn ddiffinio trawsffurfiadau newydd yn hawdd. Er enghraifft, gallwn ddiffinio peintiwr sy’n crebachu ei ddelwedd i chwarter dde uchaf y ffrâm a roddir iddo:
Trawsffurfio fframiau hefyd yw’r allwedd i ddiffinio moddion cyfuno dau beintiwr neu fwy. Mae’r weithdrefn beside, er enghraifft, yn cymryd dau beintiwr, yn eu trawsffurfio i beintio yn haneri chwith a dde ffrâm arg, yn y drefn honno, ac yn cynhyrchu peintiwr cyfansawdd newydd. Pan roddir ffrâm i’r peintiwr cyfansawdd, mae’n galw’r peintiwr trawsffurfiedig cyntaf i beintio yn hanner chwith y ffrâm ac yn galw’r ail beintiwr trawsffurfiedig i beintio yn hanner dde’r ffrâm:
Sylwch sut mae haniaeth data’r peintwyr, ac yn benodol gynrychioli peintwyr fel gweithdrefnau, yn gwneud beside yn hawdd ei gweithredu. Nid oes angen i’r weithdrefn beside wybod dim am fanylion y peintwyr cyfansoddol heblaw y bydd pob peintiwr yn llunio rhywbeth yn ei ffrâm benodedig.
Ymarfer 2.50: Diffiniwch y trawsffurfiad flip-horiz, sy’n gwrthdroi peintwyr yn llorweddol, a thrawsffurfiadau sy’n cylchdroi peintwyr 180 gradd a 270 gradd yn wrthglocwedd.
Ymarfer 2.51: Diffiniwch y gweithrediad below ar gyfer peintwyr. Mae Below yn cymryd dau beintiwr fel argiau. O gael ffrâm, mae’r peintiwr canlyniadol yn llunio â’r peintiwr cyntaf yng ngwaelod y ffrâm ac â’r ail beintiwr yn y brig. Diffiniwch below mewn dwy ffordd wahanol—yn gyntaf drwy ysgrifennu gweithdrefn sy’n cyfateb i’r weithdrefn beside a roddwyd uchod, ac eto yn nhermau beside a gweithrediadau cylchdroi addas (o Ymarfer 2.50).
Lefelau iaith ar gyfer dylunio cadarn
Mae’r iaith darluniau yn rhoi ar waith rai o’r syniadau allweddol a gyflwynasom am haniaethu â gweithdrefnau a data. Gweithredir yr haniaethau data sylfaenol, y peintwyr, drwy ddefnyddio cynrychioliadau gweithdrefnol, sy’n galluogi’r iaith i drin gwahanol alluoedd lluniadu sylfaenol mewn ffordd unffurf. Mae’r moddion cyfuno yn bodloni’r briodwedd cau, sy’n caniatáu inni adeiladu dyluniadau cymhleth yn hawdd. Yn olaf, mae’r holl offer ar gyfer haniaethu gweithdrefnau ar gael inni ar gyfer haniaethu moddion cyfuno peintwyr.
Rydym hefyd wedi cael cipolwg ar syniad hanfodol arall am ieithoedd a dylunio rhaglenni. Dyma’r dull o ddylunio haenedig, sef y syniad y dylid strwythuro system gymhleth fel dilyniant o lefelau a ddisgrifir drwy ddefnyddio dilyniant o ieithoedd. Adeiladir pob lefel drwy gyfuno rhannau a ystyrir yn gyntefig ar y lefel honno, a defnyddir y rhannau a adeiladir ar bob lefel fel elfennau cyntefig ar y lefel nesaf. Mae gan yr iaith a ddefnyddir ar bob lefel o ddyluniad haenedig elfennau cyntefig, moddion cyfuno, a moddion haniaethu sy’n briodol i’r lefel honno o fanylder.
Mae dylunio haenedig yn treiddio drwy beirianneg systemau cymhleth. Er enghraifft, mewn peirianneg gyfrifiadurol, cyfunir gwrthyddion a thransistorau (a’u disgrifio drwy ddefnyddio iaith cylchedau analog) i gynhyrchu rhannau megis adwyon AC ac adwyon NEU, sy’n ffurfio elfennau cyntefig iaith ar gyfer dylunio cylchedau digidol.97 Cyfunir y rhannau hyn i adeiladu prosesyddion, strwythurau bysiau, a systemau cof, a gyfunir yn eu tro i ffurfio cyfrifiaduron, drwy ddefnyddio ieithoedd sy’n briodol i bensaernïaeth gyfrifiadurol. Cyfunir cyfrifiaduron i ffurfio systemau dosbarthedig, drwy ddefnyddio ieithoedd sy’n briodol i ddisgrifio rhyng-gysylltiadau rhwydweithiau, ac yn y blaen.
Fel enghraifft fach o haenu, mae ein hiaith darluniau yn defnyddio elfennau cyntefig (peintwyr cyntefig) a grëir drwy ddefnyddio iaith sy’n pennu pwyntiau a llinellau i ddarparu’r rhestrau o segmentau llinell ar gyfer segments->painter, neu’r manylion cysgodi ar gyfer peintiwr fel rogers. Canolbwyntiodd y rhan fwyaf o’n disgrifiad o’r iaith darluniau ar gyfuno’r elfennau cyntefig hyn, drwy ddefnyddio cyfunwyr geometrig megis beside ac below. Buom hefyd yn gweithio ar lefel uwch, gan ystyried beside ac below yn elfennau cyntefig i’w trin mewn iaith y mae ei gweithrediadau, megis square-of-four, yn dal patrymau cyffredin o gyfuno cyfunwyr geometrig.
Mae dylunio haenedig yn helpu i wneud rhaglenni’n gadarn, hynny yw, mae’n ei gwneud yn debygol y bydd newidiadau bach mewn manyleb yn gofyn am newidiadau cyfatebol fach yn y rhaglen. Er enghraifft, tybiwch ein bod eisiau newid y ddelwedd sy’n seiliedig ar wave a ddangosir yn Ffigur 2.9. Gallem weithio ar y lefel isaf i newid golwg fanwl yr elfen wave; gallem weithio ar y lefel ganol i newid y ffordd y mae corner-split yn ailadrodd yr wave; gallem weithio ar y lefel uchaf i newid sut mae square-limit yn trefnu pedwar copi’r gornel. Yn gyffredinol, mae pob lefel o ddyluniad haenedig yn darparu geirfa wahanol ar gyfer mynegi nodweddion y system, a math gwahanol o allu i’w newid.
Ymarfer 2.52: Gwnewch newidiadau i derfyn sgwâr wave a ddangosir yn Ffigur 2.9 drwy weithio ar bob un o’r lefelau a ddisgrifiwyd uchod. Yn benodol:
Ychwanegwch rai segmentau at beintiwr cyntefig waveYmarfer 2.49 (i ychwanegu gwên, er enghraifft).
Newidiwch y patrwm a adeiladir gan corner-split (er enghraifft, drwy ddefnyddio dim ond un copi o’r delweddau up-split ac right-split yn lle dau).
Addaswch y fersiwn o square-limit sy’n defnyddio square-of-four er mwyn cydosod y corneli mewn patrwm gwahanol. (Er enghraifft, gallech wneud i’r Mr. Rogers mawr edrych allan o bob cornel o’r sgwâr.)
Troednodiadau
72 Daw’r defnydd yma o’r gair Saesneg “closure,” a gyfieithir yn “briodwedd cau,” o algebra haniaethol, lle dywedir bod set o elfennau’n gaeedig o dan weithrediad os yw cymhwyso’r gweithrediad i elfennau’r set yn cynhyrchu elfen sydd eto’n elfen o’r set. Mae cymuned Lisp hefyd (yn anffodus) yn defnyddio’r gair “closure” i ddisgrifio cysyniad hollol anghysylltiedig: Techneg weithredu ar gyfer cynrychioli gweithdrefnau â newidynnau rhydd yw caefa weithdrefnol. Nid ydym yn defnyddio’r gair “closure” yn yr ail ystyr hon yn y llyfr hwn.
73 Mae’r syniad y dylai modd cyfuno fodloni’r briodwedd cau yn syniad syml. Yn anffodus, nid yw’r cyfunwyr data a ddarperir mewn llawer o ieithoedd rhaglennu poblogaidd yn bodloni’r briodwedd cau, neu maent yn gwneud defnyddio’r briodwedd cau yn feichus. Yn Fortran neu Basic, fel arfer cyfunir elfennau data drwy eu cydosod mewn araeau—ond ni ellir ffurfio araeau y mae eu helfennau eu hunain yn araeau. Mae Pascal a C yn caniatáu strwythurau y mae eu helfennau’n strwythurau. Fodd bynnag, mae hyn yn mynnu bod y rhaglennydd yn trin pwyntyddion yn benodol, ac yn glynu wrth y cyfyngiad mai dim ond elfennau o ffurf a bennwyd ymlaen llaw y gall pob maes mewn strwythur eu cynnwys. Yn wahanol i Lisp a’i barau, nid oes gan yr ieithoedd hyn lud cyffredinol mewnol sy’n ei gwneud yn hawdd trin data cyfansawdd mewn ffordd unffurf. Y cyfyngiad hwn sydd y tu ôl i sylw Alan Perlis yn ei ragair i’r llyfr hwn: “Yn Pascal mae’r toreth o strwythurau data y gellir eu datgan yn peri arbenigo o fewn ffwythiannau sy’n atal ac yn cosbi cydweithio achlysurol. Mae’n well cael 100 o ffwythiannau’n gweithredu ar un strwythur data na chael 10 ffwythiant yn gweithredu ar 10 strwythur data.”
74 Yn y llyfr hwn, defnyddiwn rhestr i olygu cadwyn o barau a derfynir gan farciwr diwedd rhestr. Mewn cyferbyniad, mae’r term strwythur rhestr yn cyfeirio at unrhyw strwythur data a wneir o barau, nid at restrau’n unig.
75 Gan fod cymwysiadau nythol o car ac cdr yn feichus i’w hysgrifennu, mae tafodieithoedd Lisp yn darparu talfyriadau ar eu cyfer—er enghraifft,
(cadr ⟨arg⟩) = (car (cdr ⟨arg⟩))
Mae enwau pob gweithdrefn o’r fath yn dechrau ag c ac yn gorffen ag r. Mae pob a rhyngddynt yn sefyll am weithrediad car a phob d am weithrediad cdr, i’w cymhwyso yn yr un drefn ag y maent yn ymddangos yn yr enw. Mae’r enwau car ac cdr yn parhau oherwydd bod cyfuniadau syml megis cadr yn hawdd eu hynganu.
76 Mae’n rhyfeddol faint o egni wrth safoni tafodieithoedd Lisp sydd wedi’i wastraffu mewn dadleuon sydd yn llythrennol am ddim byd: A ddylai nil fod yn enw cyffredin? A ddylai gwerth nil fod yn symbol? A ddylai fod yn rhestr? A ddylai fod yn bâr? Yn Scheme, enw cyffredin yw nil, a ddefnyddiwn yn yr adran hon fel newidyn y mae ei werth yn farciwr diwedd rhestr (yn union fel y mae true yn newidyn cyffredin sydd â gwerth gwir). Mae tafodieithoedd eraill Lisp, gan gynnwys Common Lisp, yn trin nil fel symbol arbennig. Byddai awduron y llyfr hwn, sydd wedi dioddef gormod o ffraeo ynghylch safoni ieithoedd, yn hoffi osgoi’r holl fater. Unwaith y byddwn wedi cyflwyno dyfynnu yn 2.3, byddwn yn dynodi’r rhestr wag fel '() ac yn rhoi’r gorau i ddefnyddio’r newidyn nil yn llwyr.
77 I ddiffinio f ac g drwy ddefnyddio lambda byddem yn ysgrifennu
(define f (lambda (x y . z) ⟨body⟩))
(define g (lambda w ⟨body⟩))
78Mae Scheme yn darparu fel safon weithdrefn map sy’n fwy cyffredinol na’r un a ddisgrifir yma. Mae’r map mwy cyffredinol hwn yn cymryd gweithdrefn o arg, ynghyd â rhestr, ac yn cymhwyso’r weithdrefn i holl elfennau cyntaf y rhestrau, holl ail elfennau’r rhestrau, ac yn y blaen, gan ddychwelyd rhestr o’r canlyniadau. Er enghraifft:
79 Mae trefn y ddau gymal cyntaf yn yr cond yn bwysig, gan fod y rhestr wag yn bodloni null? ac hefyd nid yw’n bâr.
80 Mewn gwirionedd, dyma’r union weithdrefn fringe o Ymarfer 2.28. Yma rydym wedi’i hailenwi i bwysleisio ei bod yn rhan o deulu o weithdrefnau cyffredinol ar gyfer trin dilyniannau.
81 Datblygodd Richard Waters (1979) raglen sy’n dadansoddi rhaglenni Fortran traddodiadol yn awtomatig, gan eu hystyried yn nhermau mapiadau, hidlyddion, a gweithrediadau cronni. Canfu fod cymaint â 90 y cant o’r cod yn y Fortran Scientific Subroutine Package yn ffitio’n daclus i’r patrwm hwn. Un o’r rhesymau dros lwyddiant Lisp fel iaith raglennu yw bod rhestrau’n darparu cyfrwng safonol ar gyfer mynegi casgliadau trefnedig fel y gellir eu trin drwy ddefnyddio gweithrediadau trefn uwch. Mae’r iaith raglennu APL yn ddyledus am lawer o’i grym a’i hapêl i ddewis tebyg. Yn APL cynrychiolir yr holl ddata fel araeau, ac mae set gyffredinol a chyfleus o weithredyddion generig ar gyfer pob math o weithrediadau arae.
82 Yn ôl Knuth 1981, lluniwyd y rheol hon gan W. G. Horner yn gynnar yn y bedwaredd ganrif ar bymtheg, ond defnyddiwyd y dull mewn gwirionedd gan Newton dros gan mlynedd ynghynt. Mae rheol Horner yn gwerthuso’r polynomial drwy ddefnyddio llai o adiadau a lluosiadau na’r dull syml o gyfrifo yn gyntaf, yna ychwanegu , ac yn y blaen. Yn wir, mae’n bosibl profi bod yn rhaid i unrhyw algorithm ar gyfer gwerthuso polynomialau mympwyol ddefnyddio o leiaf gynifer o adiadau a lluosiadau â rheol Horner, ac felly mae rheol Horner yn algorithm optimwm ar gyfer gwerthuso polynomialau. Profwyd hyn (ar gyfer nifer yr adiadau) gan A. M. Ostrowski mewn papur yn 1954 a sefydlodd, i bob pwrpas, yr astudiaeth fodern o algorithmau optimwm. Profwyd y datganiad cyfatebol ar gyfer lluosiadau gan V. Y. Pan yn 1966. Mae’r llyfr gan Borodin and Munro (1975) yn darparu trosolwg o’r canlyniadau hyn a chanlyniadau eraill am algorithmau optimwm.
83 Mae’r diffiniad hwn yn defnyddio’r fersiwn estynedig o map a ddisgrifir yn Nhroednodyn 78.
84 Dangoswyd y dull hwn o ymdrin â mapiadau nythol inni gan David Turner, y mae ei ieithoedd KRC a Miranda yn darparu ffurfioliadau cain ar gyfer ymdrin â’r lluniadau hyn. Addaswyd yr enghreifftiau yn yr adran hon (gweler hefyd Ymarfer 2.42) o Turner 1981. Yn 3.5.3, gwelwn sut mae’r dull hwn yn cyffredinoli i ddilyniannau anfeidrol.
85 Rydym yn cynrychioli pâr yma fel rhestr o ddwy elfen yn hytrach nag fel pâr Lisp. Felly, cynrychiolir y “pâr” fel (list i j), nid (cons i j).
87 Defnyddir hanner colonau mewn cod Scheme i gyflwyno sylwadau. Mae’r dehonglydd yn anwybyddu popeth o’r hanner colon hyd at ddiwedd y llinell. Yn y llyfr hwn nid ydym yn defnyddio llawer o sylwadau; ceisiwn wneud i’n rhaglenni eu dogfennu eu hunain drwy ddefnyddio enwau disgrifiadol.
88 Mae’r iaith darluniau wedi’i seilio ar yr iaith a grëwyd gan Peter Henderson i adeiladu delweddau fel torlun pren M.C. Escher, “Square Limit” (gweler Henderson 1982). Mae’r torlun pren yn cynnwys patrwm graddedig sy’n ailadrodd, yn debyg i’r trefniadau a luniwyd drwy ddefnyddio’r weithdrefn square-limit yn yr adran hon.
89 William Barton Rogers (1804-1882) oedd sylfaenydd ac arlywydd cyntaf MIT. Yn ddaearegwr ac yn athro dawnus, bu’n dysgu yn William and Mary College ac yn y University of Virginia. Yn 1859 symudodd i Boston, lle roedd ganddo fwy o amser i ymchwilio, gweithiodd ar gynllun i sefydlu “athrofa bolytechnig,” a gwasanaethodd fel Arolygydd Mesuryddion Nwy cyntaf talaith Massachusetts.
Pan sefydlwyd MIT yn 1861, etholwyd Rogers yn arlywydd cyntaf arni. Roedd Rogers yn arddel delfryd o “ddysgu defnyddiol” a oedd yn wahanol i addysg brifysgol y cyfnod, gyda’i gorbwyslais ar y clasuron, a oedd, fel yr ysgrifennodd, “yn rhwystro’r addysgu a’r ddisgyblaeth ehangach, uwch a mwy ymarferol yn y gwyddorau naturiol a chymdeithasol.” Roedd yr addysg hon hefyd i fod yn wahanol i addysg gul ysgol grefftau. Yng ngeiriau Rogers:
Mae’r gwahaniaeth a orfodir gan y byd rhwng y gweithiwr ymarferol a’r gweithiwr gwyddonol yn gwbl ofer, ac mae holl brofiad yr oes fodern wedi dangos pa mor gwbl ddiwerth ydyw.
Gwasanaethodd Rogers fel arlywydd MIT hyd 1870, pan ymddiswyddodd oherwydd afiechyd. Yn 1878 ymddiswyddodd ail arlywydd MIT, John Runkle, dan bwysau argyfwng ariannol a achoswyd gan Banig 1873 a’r straen o wrthsefyll ymdrechion Harvard i gymryd MIT drosodd. Dychwelodd Rogers i ddal swydd yr arlywydd hyd 1881.
Cwympodd Rogers a bu farw wrth annerch dosbarth graddio MIT yn seremoni raddio 1882. Dyfynnodd Runkle eiriau olaf Rogers mewn anerchiad coffa a draddodwyd yr un flwyddyn:
“Wrth imi sefyll yma heddiw a gweld beth yw’r Athrofa, … galwaf i gof ddechreuadau gwyddoniaeth. Cofiaf fod Stephen Hales, gant a hanner o flynyddoedd yn ôl, wedi cyhoeddi pamffled ar bwnc nwy goleuo, lle dywedodd fod ei ymchwiliadau wedi dangos bod 128 graen o lo bitwminaidd – ” “Glo bitwminaidd,” dyna oedd ei eiriau olaf ar y ddaear. Yma plygodd ymlaen, fel pe bai’n edrych ar rai nodiadau ar y bwrdd o’i flaen, yna’n araf sythodd unwaith eto, cododd ei ddwylo, ac fe’i cludwyd o olygfa ei lafur a’i fuddugoliaethau daearol i “yfory marwolaeth,” lle datrysir dirgelion bywyd, a lle mae’r ysbryd heb gorff yn canfod boddhad diddiwedd wrth fyfyrio ar ddirgelion newydd, ac eto annirnadwy, y dyfodol anfeidrol.
Yng ngeiriau Francis A. Walker (trydydd arlywydd MIT):
Ar hyd ei oes roedd wedi ymddwyn yn dra ffyddlon ac arwrol, a bu farw fel y byddai marchog mor dda yn sicr wedi dymuno, yn ei harnais, yn ei swydd, ac yng nghanol cyflawni ei ddyletswydd gyhoeddus.
91 Mae Rotate180 yn cylchdroi peintiwr 180 gradd (gweler Ymarfer 2.50). Yn lle rotate180 gallem ddweud (compose flip-vert flip-horiz), drwy ddefnyddio’r weithdrefn compose o Ymarfer 1.42.
92 Mae Frame-coord-map yn defnyddio’r gweithrediadau fector a ddisgrifir yn Ymarfer 2.46 isod, y tybiwn eu bod wedi’u gweithredu drwy ddefnyddio rhyw gynrychioliad ar gyfer fectorau. Oherwydd haniaethu data, nid oes ots beth yw’r cynrychioliad fector hwn, cyn belled â bod y gweithrediadau fector yn ymddwyn yn gywir.
93 Mae Segments->painter yn defnyddio’r cynrychioliad ar gyfer segmentau llinell a ddisgrifir yn Ymarfer 2.48 isod. Mae hefyd yn defnyddio’r weithdrefn for-each a ddisgrifir yn Ymarfer 2.23.
94 Er enghraifft, adeiladwyd peintiwr rogersFfigur 2.11 o ddelwedd lefelau llwyd. Ar gyfer pob pwynt mewn ffrâm benodol, mae’r peintiwr rogers yn pennu’r pwynt yn y ddelwedd a fapir iddo o dan fapiad cyfesurynnau’r ffrâm, ac yn ei gysgodi’n unol â hynny. Drwy ganiatáu gwahanol fathau o beintwyr, rydym yn manteisio ar y syniad o ddata haniaethol a drafodwyd yn 2.1.3, lle dadleuasom y gallai cynrychioliad rhifau cymarebol fod yn unrhyw beth o gwbl sy’n bodloni amod priodol. Yma rydym yn defnyddio’r ffaith y gellir gweithredu peintiwr mewn unrhyw ffordd o gwbl, cyn belled â’i fod yn llunio rhywbeth yn y ffrâm benodedig. Dangosodd 2.1.3 hefyd sut y gellid gweithredu parau fel gweithdrefnau. Peintwyr yw ein hail enghraifft o gynrychioliad gweithdrefnol o ddata.
95 Dim ond ar gyfer fframiau sgwâr y mae Rotate90 yn gylchdroad pur, oherwydd ei fod hefyd yn ymestyn ac yn crebachu’r ddelwedd i ffitio yn y ffrâm a gylchdrowyd.
96 Crëwyd y delweddau ar ffurf diemwnt yn Ffigur 2.10 a Ffigur 2.11 drwy gymhwyso squash-inwards i wave ac rogers.
97 Mae Adran 3.3.4 yn disgrifio un iaith o’r fath.