Du er nå ferdig med variablar og funksjonar, og er klar for det skumle området av Scheme som handlar om lister.
Før vi ser meir på dette med lister, er det viktig at du kjenner skilnaden på delverdiar (av og til i programmerarverda kalla “atomverdiar”) og lister.
Ein delverdi er ein enkeltverdi. Vi brukte delverdiar då vi definerte variablar og tileigna desse ein verdi tidlegare i kurset. Som eit eksempel kan vi tileigna variabelen “x” delverdien “8” i dette uttrykket:
(let* ( (x 8) ) x)
(Her er variabelen x
lagt til på slutten av
uttrykket bare for å få skrive ut verdien av x
.
Dette fordi let*
arbeider akkurat som ein funksjon
og returnerer verdien i det siste uttrykket.
Ein variabel kan også referere til ei liste med verdiar i staden
for bare til ein enkelt verdi. For å tileigna verdilista 1, 3, 5 til
variabelen x
skriv vi:
(let* ( (x '(1 3 5))) x)
Prøv begge setningane i Script-Fu konsollen og legg merke til svaret du får. Når du skriv den første setning, blir svaret
8
Den andre setning vil gi svaret:
(1 3 5)
Svaret “8” fortel at x inneheld “atomverdien” “8”. Svaret (1 3 5) viser at x ikkje inneheld ein enkelt verdi, men ei liste med verdiar. Legg merke til at Scheme ikkje bruker komma mellom verdiane, verken i den lista du skriv inn eller i det svaret du får ut att.
For å definera ei liste, brukar du syntaksen:
'(a b c)
der a
, b
og
c
er verdiane. Apostrofen (') blir nytta for å
fortelje at det som kjem etter inne i parentesen er ei liste med
verkelege verdiar, ikkje funksjonar eller uttrykk.
Du kan også definere ei tom liste:
'()
eller bare
()
Ei liste kan innehalde direkteverdiar, eller nye lister:
(let* ( (x '("The GIMP" (1 2 3) ("is" ("great" () ) ) ) ) ) x )
Legg merke til at det er nok med den første apostrofen. Prøv programmet i konsollen og sjå kva som kjem ut av det.
Du bør også merka deg at det resultatet som blir returnert ikkje er
ei liste med enkeltverdiar, men ei liste med samla verdiar.
("GIMP")
, lista (1 2 3)
osv.
Ofte kan det vere greitt å sjå på listene som om dei er sett saman av eit “hovud” og ein “hale”. Hovudet er det første elementet i lista, medan halen er resten av lista. Verkar kanskje noe merkeleg, men som du vil sjå seinare, er dette ikkje noen dum tenkemåte.
Ein av dei mest brukte innebygde funksjonane er funksjonen
cons
. Denne tar ein verdi og kjedar han saman med
verdien frå det andre elementet, som er ei liste, og lagar ei ny
liste. Frå det som blei sagt tidlegare, kan du sjå på ei liste som
sett saman av eit element (hovudet) og resten av lista (halen).
Det er også slik cons
gjer det. Funksjonen legg eit
element til hovudet på lista. Lagar du ei liste slik:
(cons 1 '(2 3 4) )
vil resultatet bli den nye lista (1 2 3 4)
.
Du kan også lage ei liste med bare eitt element:
(cons 1 () )
Sjølvsagt kan du nytta tidlegare definerte variablar i listene i staden for direkteverdiane.
For å definera ei liste med ei blanding av direkteverdiar og
tidlegare deklarerte variablar, nyttar du funksjonen list
:
(list 5 4 3 a b c)
Dette vil lage og returnera ei liste med ei blanding av direkteverdiane
“5”, “4” og “3”, og verdiane
som er tileigna variablane a
,
b
og c
. Vi prøver med:
(let* ( (a 1) (b 2) (c 3) ) (list 5 4 3 a b c) )
Dette vil resultera i lista (5 4 3 1 2 3)
.
Får å få tilgang til verdiane i ei liste bruker vi funksjonane
car
og cdr
. car
returnerar
verdien av det første elementet i lista, hovudet, medan
cdr
returnerar resten av lista, halen. Som nemnd
tidlegare kan ein sjå på ei liste som sett saman av hovud og hale.
car
returnerar det første elementet i ei liste,
altså listehovudet. Dersom lista er tom, vil returverdien bli ei
tom liste.
(car '("first" 2 "third"))
vil gi tilbake:
"first"
cdr
returnerar resten av lista, halen. Dersom det
bare er eitt element i lista, vil returverdien bli ei tom liste.
(cdr '("first" 2 "third"))
returnerar:
(2 "third")
medan
(cdr '("one and only"))
returnerar
()
Vi kan altså nokså enkelt plukke ut listehovudet og listehalen, men kva om du ønskjer å ta ut verdien av det tredje elementet i ei liste? Det er fullt mogleg, men Scheme har ein noe merkeleg, og tungvindt, måte å gjere det på i høve til andre språk. Du må rett og slett plukka ut hovudet til halen passeleg mange gonger til du kjem fram til det elementet du ønskjer. Eksempel:
Vi har lista (“ein” “to” “tre” “fire” “fem”) og ønskjer å ta ut det tredje elementet, “tre”. Først tar vi ut den siste delen av lista med
Resultatet blir den nye lista ("to" "tre" "fire" "fem"). Deretter tar vi ut den siste delen av denne nye lista:
og ender opp med lista ("tre" "fire" "fem"). Tar vi nå ut hovudet på denne siste lista,
vil vi endeleg sitje att med det tredje elementet. Køyrer vi dette saman på ei linje, får vi
eller på ein “enklare” måte:
Dersom du framleis er med, skal eg gjere eit forsøk på å forklare denne mystiske kommandoen. Ser vi på linja
er ho tilsynelatande sett saman av kommandoane car
,
cdr
og cdr
. Den eigentlege kommandoen
er c...r
. Innimellom desse bokstavane set du
bokstaven “a” for listehovudet og “d”
for listehalen. Ein “a” for det første hovudet,
“d” for halen og “d” for halen. Eit
anna eksempel. Uttrykket
(car (cdr (car x) ) )
kan altså trekkast saman til
(cadar x)
Du kan finne meir om listefunksjonen i tillegg A, som også inneheld ei liste over tilgjengelege funksjonar i den versjonen av Scheme som blir brukt i Script-Fu.
Som ei trening, kan du prøve dette eksemplet. Bruker du
Script-Fu konsollen, må du skrive alt på ei linje. Bruk ulike
variasjonar av car
og cdr
for å plukke
ut ulike element frå lista.
(let* ( (x '( (1 2 (3 4 5) 6) 7 8 (9 10) ) ) ) ; place your car/cdr code here )
Greier du å plukke ut talet 3 i lista med bare to funksjonskall, er du langt på vegen til å bli ein meister i Script-Fu.
Notat | |
---|---|
I Scheme kan du nytte semikolon (“;”) for å skrive ein kommentar. Semikolonet, og alt som kjem etter dette på same linja, blir ignorert av skriptomsetjaren. Bruk dette flittig. Det er mykje enklare å finne fram i eit skript som er godt kommentert, særleg når det har gått ei tid sidan du endra det. |