3.3. Zoznamy, zoznamy a zase zoznamy

Takže už ste zvládli premenné aj funkcie, je čas vstúpiť do temných bažín, ktoré v Scheme predstavujú zoznamy (angl. list).

3.3.1. Definovanie zoznamu

Prv než začneme zoznamy rozoberať hlbšie je potrebné, aby ste pochopili rozdiel medzi atomickými hodnotami a zoznamami.

Z atomickými hodnotami sme sa už stretli keď sme v predchádzajúcej lekcii inicializovali premenné. Atomická hodnota je jednoducho hodnota. V nasledujúcom príklade si ukážeme, ako premennej x priradíme hodnotu 8.

(let* ( (x 8) ) x)

(Výraz x sme umiestnili na koniec len preto, aby sa vypísala hodnota priradená premennej x. Pri bežnom písaní skriptov to nie je nutné robiť takto. Všimnite si, že let* pracuje podobne ako funkcia: vracia hodnotu posledného výroku.)

Premenná môže odkazovať nielen na jednoduchú hodnotu, ale aj na zoznam hodnôt. Definovanej premennej x priradíme hodnoty 1, 3, 5 týmto spôsobom:

(let* ( (x '(1 3 5))) x)

Skúste napísať oba výroky do konzoly Script-Fu a sledujte reakcie. Po zadaní prvého výroku dostanete jednoduchý výsledok:

8

Avšak po napísaní druhého výroku dostanete nasledujúci výsledok:

(1 3 5)

Ak dostanete odpoveď s hodnotou 8, znamená to, že premenná x obsahuje atomickú hodnotu 8. Odpoveď s výsledkom (1 3 5) však hovorí, že x neobsahuje iba jednu hodnotu, ale zoznam hodnôt. Všimnite si, že v deklarácii, vo výroku zoznamu, ani vo vypísanom výsledku nie sú čiarky.

Syntax definovania zoznamu je nasledovná:

'(a b c)

kde a, b a c sú literály. Apostrof (') naznačuje, že to, čo nasleduje v zátvorkách, je zoznam hodnôt literálov, teda nie funkcia alebo výraz.

Prázdny zoznam môže byť definovaný takto:

'()

alebo jednoducho:

()

Zoznamy môžu obsahovať atomické hodnoty ako aj iné zoznamy:

(let*
   (
        (x
           '("GIMP" (1 2 3) ("je" ("super" () ) ) )
        )
    )
    x
)
      

Všimnite si, že ak chcete definovať vnútorný zoznam, za prvým apostrofom už nie je ďalší apostrof nutný. Kľudne výrok skopírujte do konzoly Script-Fu a pozorujte výsledok.

Môžete vidieť, že vrátený výsledok nie je zoznam jednoduchých, atomických hodnôt ale skôr zoznam pozostávajúci z literálu ("GIMP"), zoznamu (1 2 3) atď.

3.3.2. Ako si zoznamy predstaviť

Zoznamy si môžeme predstaviť ako o útvary zložené z hlavičky (head) a chvosta (tail). Hlava predstavuje prvý prvok zoznamu, chvost zvyšok zoznamu. Prečo je to dôležité uvidíte neskôr, keď si ukážeme ako prvky do zoznamu pridávať a ako ich vyberať.

3.3.3. Tvorba zoznamov spájaním (Funkcia Cons)

Jedna z funkcií, s ktorou sa bude stretávať najčastejšie, je funkcia cons. Táto funkcia vezme hodnotu a vloží ju k jej druhému argumentu, k zoznamu. V predchádzajúcej časti som navrhol predstavu zoznamu ako útvaru zloženého z prvku (hlavička) a zvyšku zoznamu (chvost). Presne takto funkcia cons pracuje - pridáva element k hlavičke zoznamu. Takto môžete vytvoriť nasledujúci zoznam:

(cons 1 '(2 3 4) )

Výsledkom je zoznam (1 2 3 4).

Vytvoriť môžete aj zoznam obsahujúci iba jeden element:

(cons 1 () )

Namiesto ľubovoľného literálu môžete použiť už deklarované premenné.

3.3.4. Definovanie zoznamu pomocou funkcie list

Funkcia list sa používa na definovanie zoznamu zloženého z literálov alebo už deklarovaných premenných.

(list 5 4 3 a b c)

Tak sa vytvorí a vráti zoznam obsahujúci hodnoty priradené k premenným a, b a c. Napríklad:

        (let*  (
                  (a 1)
                  (b 2)
                  (c 3)
               )

               (list 5 4 3 a b c)
        )
      

Tento kód vytvorí zoznam (5 4 3 1 2 3).

3.3.5. Prístup k hodnotám v zozname

K hodnotám v zozname pristupujete pomocou funkcií car a cdr. Kým prvá z nich vráti prvý prvok v zozname, druhá funkcia vráti ostatok zoznamu. Tieto funkcie zoznam rozdelia podľa pravidla hlavička::chvost, ako som spomínal vyššie.

3.3.6. Funkcia car

Funkcia car vracia prvý prvok zoznamu (hlavička zoznamu). Zoznam musí byť nenulový. Takže nasledujúci zápis vráti prvý prvok zoznamu:

(car '("prvý" 2 "tretí"))

čo znamená:

"prvý"

3.3.7. Funkcia cdr

Funkcia cdr vráti všetko, čo nasleduje po prvom prvku v zozname (chvost zoznamu). Ak je na prvom mieste iba jeden prvok, funkcia vráti prázdny zoznam.

(cdr '("prvý" 2 "tretí"))

vráti:

(2 "tretí")

kým nasledujúci:

(cdr '("jeden jediný"))

vráti:

()

3.3.8. Prístup k ďalším prvkom zoznamu

Výborne! Teraz už vieme, ako získať prvý a posledný prvok zoznamu. Ale ako sa dostať k tým ostatným, t. j. k druhému, tretiemu atď.? Vybrať si môžete z niekoľkých príjemných funkcií, napr. hlavička hlavičky chvosta zoznamu (caadr), chvost chvosta zoznamu (cddr), atď.

Základná konvencia pomenovania takýchto funkcií je jednoduchá: písmeno a a d predstavujú hlavičky a chvosty zoznamov, takže

(car (cdr (car x) ) )

je možné zapísať aj ako:

(cadar x)

Aby ste si funkcie pre prístup k zoznamom precvičili, napíšte nasledujúce (ak však používate konzolu, všetko musí byť na jednom riadku); vyskúšajte rôzne obmeny car a cdr na prístup k rôznym prvkom zoznamu:

        (let*  (
                 (x  '( (1 2 (3 4 5) 6)  7  8  (9 10) )
                 )
              )
              ; sem napíšte kódy car/cdr
        )
      

Zo zoznamu sa pokúste získať číslo 3 použitím iba dvoch volaní funkcií. Ak to dokážete, možno ste na dobrej ceste stať sa majstrom Script-Fu.

[Note] Poznámka

V Scheme sa bodkočiarkou (;) označuje poznámka. Bodkočiarka a všetko, čo nasleduje za ňou bude interprétor ignorovať. Do poznámok si môžete zapísať komentár, ktorý vám v budúcnosti môže pomôcť rozpamätať sa, ak sa na skript pozriete po dlhšej dobe.