3.3. Списки, списки и ещё раз списки
| 3. Инструкция по Script-Fu |

### 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` возвращает первый элемент списка (голова списка). Список не может быть пустой. Следующее выражение вернёт первое значение:

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

то есть

    "первый"

#### 3.3.7. Функция `cdr`

`cdr` возвращает остаток списка после первого элемента (хвост списка). Если в списке только один элемент, то возвращается пустой список.

    (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!

| Примечание
В Scheme точка с запятой (`;`) указывает на комментарий. Всё, что следует за ней, игнорируется интерпретатором сценариев. Поэтому, используйте комментарии для пометок и описания сложных выражений, чтобы не забыть, что они делают.

3.2. Переменные и функции |  | 3.4. Первый сценарий Script-Fu

Report an error in Bugzilla