3.3. Списки, списки и ещё раз списки

Теперь, когда вы знаете о переменных и функциях, обратимся к спискам в Scheme.

3.3.1. Определение списка

До разговора о списках необходимо упомянуть разницу между неделимыми значениями и списками.

В предыдущем уроке вы уже видели неделимые значения, которые мы присвоили переменным. Неделимое значение — это одно-единственное значение. Так, мы можем присвоить переменной «x» значение 8 следующим утверждением:

(let* ( (x 8) ) x)

Мы добавили выражение x в конце, чтобы вывести значение переменной x. Обычно этого не требуется. Заметьте, что оператор let* ведёт себя как функция: возвращается значение последнего выражения.

Переменная также может содержать спискок значений вместо одного значения. Чтобы присвоить переменной x список значений 1, 3, 5, нужно ввести:

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

Попробуйте ввести оба утверждения в консоль Script-Fu и посмотрите, что они выводят.

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
)
      

Заметьте, что после первого апострофа не надо больше ставить апостроф перед внутренними списками. Введите это выражение и посмотрите, что получится.

Вы заметите, что возвращённый результат — не список одиночных неделимых значений, а список, содержащий буквальное значение (The GIMP), список (1 2 3) и т.д.

3.3.2. Как думать о списках

Полезно думать о списках, как состоящих из «головы» и «хвоста». Голова — первый элемент списка, хвост — остаток списка. Вы увидите, почему это важно, как речь пойдёт о сложении списков и о доступе к элементам списка.

3.3.3. Создание списков сцеплением (Функция Cons)

Наиболее употребляемая функция это функция cons. Она берёт любое значение и добавляет его ко второму параметру, списку. Если использовать терминологию вышесказанного, это функция добавляет значение в голове списка. Поэтому список можно создать следующим образом:

(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 returns the first element of the list (the head of the list). The list needs to be non-null (not empty). Thus, the following returns the first element of the list:

(car '("первый" 2 "третий"))

то есть

"первый"

3.3.7. Функция cdr

cdr returns the remainder 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 '("первый" 2 "третий"))

возвращает

(2 "третий")

тогда как

(cdr '("один единственный"))

возвращает

()

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 из списка при помощи только двух вызовов функций. Если сможете, то вы на правильном пути стать мастером Script-Fu!

[Примечание] Примечание

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