3.3. Seznamy, seznamy a zase seznamy

Již umíte pracovat s proměnnými a funkcemi, je na čase vydat se za tajemstvím seznamů (anglicky lists, které tvoří důležitou součást Scheme.

3.3.1. Definování seznamu

Dříve, než si o seznamech povíme více, musíte pochopit rozdíl mezi atomickými hodnotami a seznamy.

You've already seen atomic values when we initialized variables in the previous lesson. An atomic value is a single value. So, for example, we can assign the variable x the single value of 8 in the following statement:

(let* ( (x 8) ) x)

(We added the expression x at the end to print out the value assigned to x—normally you won't need to do this. Notice how let* operates just like a function: The value of the last statement is the value returned.)

Proměnná může také odkazovat na seznam hodnot, ne na hodnotu jedinou. Přiřadit proměnné x seznam hodnot 1, 3, 5 lze takto:

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

Zkuste oba výroky ve Script-Fu konzoli a sledujte reakci. První výrok vrátí výsledek:

8

Druhý výrok však vrátí následující výsledek:

(1 3 5)

When it replies with the value 8 it is informing you that x contains the atomic value 8. However, when it replies with (1 3 5), it is then informing you that x contains not a single value, but a list of values. Notice that there are no commas in our declaration or assignment of the list, nor in the printed result.

Syntaxe definice seznamu je následující:

'(a b c)

where a, b, and c are literals. We use the apostrophe (') to indicate that what follows in the parentheses is a list of literal values, rather than a function or expression.

Prázdný seznam lze definovat následujícím způsobem:

'()

nebo jednodušeji:

()

Seznamy mohou obsahovat atomické hodnoty i další seznamy:

(let*
   (
        (x
           '("GIMP" (1 2 3) ("is" ("great" () ) ) )
        )
    )
    x
)
      

Všimněte si, že za prvním apostrofem již není, pro vnitřní seznamy, apostrofy používat. Přepiště výrok do jedné řádky, vložte do Script-Fu konzole, vyzkoušejte a prohlédněte si výsledek.

Vrácený výsledek není seznam jednotlivých atomických hodnot, ale obsahuje literál ("GIMP"), seznam (1 2 3) atd.

3.3.2. Kterak přemýšlet o seznamech

O seznamech je často užitečné přemýšlet jako o útvarech složených z hlavičky a ocásku (anglicky head a tail). Hlavička je první položka seznamu, zbývající položky tvoří ocásek. Bude to užitečné, až budeme mluvit o spojování seznamů a přístupu k jednotlivým prvkům seznamu.

3.3.3. Vytváření seznamů spojováním (funkce cons)

One of the more common functions you'll encounter is the cons function. It takes a value and places it to its second argument, a list. From the previous section, I suggested that you think of a list as being composed of an element (the head) and the remainder of the list (the tail). This is exactly how cons functions — it adds an element to the head of a list. Thus, you could create a list as follows:

(cons 1 '(2 3 4) )

Výsledkem je seznam (1 2 3 4).

Lze takto vytvořit i seznam s jedním prvkem:

(cons 1 () )

Místo kteréhokoliv literálu můžete samozřejmě použít dříve deklarovanou proměnnou.

3.3.4. Definice seznamu pomocí funkce list

To define a list composed of literals or previously declared variables, use the list function:

(list 5 4 3 a b c)

Tak se vytvoří a vrátí seznam obsahující hodnoty proměnných a, b a c. Například:

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

               (list 5 4 3 a b c)
        )
      

Tento kód vytvoří seznam (5 4 3 1 2 3).

3.3.5. Přístupování k hodnotám v seznamu

To access the values in a list, use the functions car and cdr, which return the first element of the list and the rest of the list, respectively. These functions break the list down into the head::tail construct I mentioned earlier.

3.3.6. The car Function

car returns the first element of the list (the head of the list). The list needs to be non-null. Thus, the following returns the first element of the list:

(car '("first" 2 "third"))

vrátí:

"first"

3.3.7. The cdr function

cdr returns the rest of the list after the first element (the tail of the list). If there is only one element in the list, it returns an empty list.

(cdr '("first" 2 "third"))

vrací:

(2 "third")

zatímco následující:

(cdr '("one and only"))

vrací:

()

3.3.8. Přístup k dalším prvkům v seznamu

Výborně, již umíme získat první prvek ze seznamu i zbytek seznamu. Jak ale přistupovat ke druhému, třetímu nebo jinému prvku seznamu? K tomuto účelu existuje řada praktických funkcí, např. hlavička hlavičky ocásku seznamu (caadr), ocásek ocásku seznamu (cddr) atd.

Konvence pro pojemnovávání takových to funkcí je velmi jednoduchá. Písmena a představují hlavičky, písmena d představují ocásky. Například:

(car (cdr (car x) ) )

lze jednodušeji zapsat jako:

(cadar x)

To get some practice with list-accessing functions, try typing in the following (except all on one line if you're using the console); use different variations of car and cdr to access the different elements of the list:

        (let* (
                 (x  '( (1 2 (3 4 5) 6)  7  8  (9 10) )
                 )
              )
              ; place your car/cdr code here
        )
      

Pokuste se získat číslo tři pouze dvěma voláními funkce. Pokud se vám to podaří, možná se z vás stane Mistr Script-Fu!

[Poznámka] Poznámka

In Scheme, a semicolon (;) marks a comment. It, and anything that follows it on the same line, are ignored by the script interpreter, so you can use this to add comments to jog your memory when you look at the script later.