3.3. Спискови, спискови и још спискова

Обучили смо вас за рад са променљивама и функцијама, а сада улазимо у мутне воде Скимових спискова.

3.3.1. Дефинисање списка

Пре него што почнемо да причамо више о списковима, неопходно је да знате разлику између атомских вредности и спискова.

Већ сте видели атомске вредности када смо иницијализовали променљиве у претходној лекцији. Атомска вредност је појединачна вредност. Тако, на пример, можемо доделити променљивој „x“ појединачну вредност 8 у следећој наредби:

(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.)

Променљива се такође може односити на списак вредности, уместо на појединачну вредност. Да бисмо променљивој x доделили списак вредности 1, 3, 5, куцали бисмо:

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

Пробајте да унесете обе наредбе у Скрипт-фу конзолу и приметићете како она одговара. Када унесете прву наредбу, она једноставно одговара резултатом:

8

Међутим, када унесете другу наредбу, она одговара следећим резултатом:

(1 3 5)

Када одговори вредношћу 8, она вас обавештава да x садржи атомску вредност 8. Међутим, када одговори са (1 3 5), она вас обавештава да x не садржи појединачну вредност, већ списак вредности. Приметите да нема запета у нашој декларацији или додели списка, као ни у одштампаном резултату.

Синтакса за дефинисање списка је:

'(a b c)

где су a, b и c литерали. Користимо апостроф (') да означимо да је оно што следи унутар заграда списак дословних вредности, а не функција или израз.

Празан списак се може дефинисати на следећи начин:

'()

или једноставно:

()

Спискови могу садржати атомске вредности, као и друге спискове:

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

Приметите да након првог апострофа више не морате да користите апостроф приликом дефинисања унутрашњих спискова. Слободно копирајте овај израз у Скрипт-Фу конзолу и погледајте шта враћа.

Требало би да приметите да враћени резултат није списак појединачних, атомских вредности; већ је то списак литерала ("GIMP"), списак (1 2 3), итд.

3.3.2. Како размишљати о списковима

Корисно је размишљати о списковима као о нечему што се састоји од „главе“ (head) и „репа“ (tail). Глава је први елемент списка, а реп је остатак списка. Видећете зашто је ово важно када будемо разговарали о томе како се додаје у спискове и како се приступа елементима у списку.

3.3.3. Прављење спискова путем спајања (функција 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) )

Резултат је списак (1 2 3 4).

Такође бисте могли да направите списак са једним елементом:

(cons 1 () )

Можете користити претходно декларисане променљиве уместо било којих литерала, као што бисте и очекивали.

3.3.4. Дефинисање списка помоћу функције list

Да бисте дефинисали списак састављен од литерала или претходно декларисаних променљивих, користите функцију list:

(list 5 4 3 a b c)

Ово ће саставити и вратити списак који садржи вредности променљивих a, b и c. На пример:

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

               (list 5 4 3 a b c)
        )
      

Овај код прави списак (5 4 3 1 2 3).

3.3.5. Приступање вредностима у списку

За приступање вредностима у списку, користите функције car и cdr, које враћају први елемент списка, односно остатак списка. Ове функције разлажу списак на структуру глава::реп коју сам раније поменуо.

3.3.6. Функција car

car враћа први елемент списка (главу списка). Списак не сме бити празан (non-null). Тако следеће враћа први елемент списка:

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

који је:

"first"

3.3.7. Функција cdr

cdr враћа остатак списка након првог елемента (реп списка). Ако у списку постоји само један елемент, враћа празан списак.

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

враћа:

(2 "third")

док следеће:

(cdr '("one and only"))

враћа:

()

3.3.8. Приступање осталим елементима у списку

У реду, сјајно, можемо да добијемо први елемент листе, као и остатак листе, али како да приступимо другом, трећем или осталим елементима листе? Постоји неколико „погодних“ функција за приступање, на пример, глави главе репа листе (caadr), репу репа листе (cddr), итд.

Основно правило именовања је једноставно: слова „a“ и „d“ представљају главе и репове листи, тако да

(car (cdr (car x) ) )

може бити записано као:

(cadar x)

Да бисте мало вежбали са функцијама за приступање листи, покушајте да укуцате следеће (осим што све иде у један ред ако користите конзолу); користите различите варијације функција car и cdr за приступање различитим елементима листе:

        (let* (
                 (x  '( (1 2 (3 4 5) 6)  7  8  (9 10) )
                 )
              )
              ; овде поставите ваш car/cdr код
        )
      

Покушајте да приступите броју 3 у листи користећи само два позива функције. Ако то успете, на добром сте путу да постанете мајстор Скрипт-фуа!

[Примедба] Примедба

У Шеми (Scheme), тачка-зарез (;) означава почетак коментара. Њега, и све што следи у истом реду, тумач скрипти занемарује, тако да то можете користити за додавање коментара како бисте освежили памћење када касније будете гледали скрипту.