Ремонт принтеров, сканнеров, факсов и остальной офисной техники


назад Оглавление вперед




[33]

получить с помощью (list 1 2 3 4). В общем случае (list {a1) {a2) ... {an))

эквивалентно

(cons {a1) (cons{a2) (cons ... (cons {an) nil) ... )))

По традиции, Лисп-системы печатают списки в виде последовательности их элементов, заключенной в скобки. Таким образом, объект данных с рисунка 2.4 выводится как (1 2 3 4) :

(define one-through-four (list 12 3 4))

one-through-four (1 2 3 4)

Внимание: не путайте выражение (list 1 2 3 4) со списком (1 2 3 4) , который является результатом вычисления этого выражения. Попытка вычислить выражение (1 2 3 4) приведет к сообщению об ошибке, когда интерпретатор попробует применить процедуру 1 к аргументам 1, 2, 3 и 4.

Мы можем считать, что процедура car выбирает первый элемент из списка, а cdr возвращает подсписок, состоящий из всех элементов, кроме первого. Вложенные применения car и cdr могут выбрать второй, третий и последующие элементы списка.9 Конструктор cons порождает список, подобный исходному, но с дополнительным элементом в начале.

(car one-through-four)

1

(cdr one-through-four)

(2 3 4)

(car (cdr one-through-four))

2

(cons 10 one-through-four) (10 1 2 3 4)

(cons 5 one-through-four) (51234)

Значение nil, которым завершается цепочка пар, можно рассматривать как последовательность без элементов, пустой список (empty list). Слово nil произошло от стяжения латинского nihil, что значит «ничто».10

9Поскольку записывать вложенные применения car и cdr громоздко, в диалектах Лиспа существуют сокращения - например,

(cadr {ара)) = (car (cdr {ара)))

У всех таких процедур имена начинаются с с, а кончаются на r. Каждое a между ними означает операцию car, а каждое d операцию cdr, и они применяются в том же порядке, в каком идут внутри имени. Имена car и cdr сохраняются, поскольку простые их комбинации вроде cadr нетрудно произнести.

10Удивительно, сколько энергии при стандартизации диалектов Лиспа было потрачено на споры буквально ни о чем: должно ли слово nil быть обычным именем? Должно ли значение nil


Операции со списками

Использованию пар для представления последовательностей элементов в виде списков сопутствуют общепринятые методы программирования, которые, работая со списками, последовательно их «уcdrивают». Например, процедура list-ref берет в качестве аргументов список и число n и возвращает n-й элемент списка. Обычно элементы списка нумеруют, начиная с 0. Метод вычисления list-ref следующий:

•Если n = 0, list-ref должна вернуть car списка.

•В остальных случаях list-ref должна вернуть (n - 1)-й элемент от cdr списка.

(define (list-ref items n)

(if (= n 0)

(car items)

(list-ref (cdr items) (- n 1))))

(define squares (list 1 4 9 16 25))

(list-ref squares 3)

16

Часто мы проcdrиваем весь список. Чтобы помочь нам с этим, Scheme включает элементарную процедуру null?, которая определяет, является ли ее аргумент пустым списком. Процедура length, которая возвращает число элементов в списке, иллюстрирует эту характерную схему использования операций над списками:

(define (length items)

(if (null? items) 0

(+ 1 (length (cdr items)))))

(define odds (list 13 5 7))

(length odds) 4

Процедура length реализует простую рекурсивную схему. Шаг редукции таков:

•Длина любого списка равняется 1 плюс длина cdr этого списка

Этот шаг последовательно применяется, пока мы не достигнем базового случая:

•Длина пустого списка равна 0.

Мы можем вычислить length и в итеративном стиле:

являться символом? Должно ли оно являться списком? Парой? В Scheme nil - обычное имя, и в этом разделе мы используем его как переменную, значение которой - маркер конца списка (так же, как true - это обычная переменная, значение которой истина). Другие диалекты Лиспа, включая Common Lisp, рассматривают nil как специальный символ. Авторы этой книги пережили слишком много скандалов со стандартизацией языков и хотели бы не возвращаться к этим вопросам. Как только в разделе 2.3 мы введем кавычку, мы станем обозначать пустой список в виде (), а от переменной nil полностью избавимся.


(define (length items)

(define (length-iter a count)

(if (null? a)

count

(length-iter (cdr a) (+ 1 count)))) (length-iter items 0))

Еще один распространенный программистский прием состоит в том, чтобы «сconsить» результат по ходу уcdrивания списка, как это делает процедура append, которая берет в качестве аргументов два списка и составляет из их элементов один общий список:

(append squares odds) (1 4 9 16 25 1 3 5 7)

(append odds squares)

(1 3 5 7 1 4 9 16 25)

Append также реализуется по рекурсивной схеме. Чтобы соединить списки list1 и list2 , нужно сделать следующее:

•Если список list1 пуст, то результатом является просто list2.

•В противном случае, нужно соединить cdr от list1 с list2, а к результату прибавить car от list1 с помощью cons:

(define (append list1 list2)

(if (null? list1) list2

(cons (car list1) (append (cdr list1) list2)))) Упражнение 2.17.

Определите процедуру last-pair, которая возвращает список, содержащий только последний элемент данного (непустого) списка.

(last-pair (list 23 72 149 34))

(34)

Упражнение 2.18.

Определите процедуру reverse, которая принимает список как аргумент и возвращает список, состоящий из тех же элементов в обратном порядке:

(reverse (list 1 4 9 16 25))

(25 16 9 4 1) Упражнение 2.19.

Рассмотрим программу подсчета способов размена из раздела 1.2.2. Было бы приятно иметь возможность легко изменять валюту, которую эта программа использует, так, чтобы можно было, например, вычислить, сколькими способами можно разменять британский фунт. Эта программа написана так, что знание о валюте распределено между процедурами first-denomination и count-change (которая знает, что существует пять видов американских монет). Приятнее было бы иметь возможность просто задавать список монет, которые можно использовать при размене.

Мы хотим переписать процедуру cc так, чтобы ее вторым аргументом был список монет, а не целое число, которое указывает, какие монеты использовать. Тогда у нас могли бы быть списки, определяющие типы валют:



[стр.Начало] [стр.1] [стр.2] [стр.3] [стр.4] [стр.5] [стр.6] [стр.7] [стр.8] [стр.9] [стр.10] [стр.11] [стр.12] [стр.13] [стр.14] [стр.15] [стр.16] [стр.17] [стр.18] [стр.19] [стр.20] [стр.21] [стр.22] [стр.23] [стр.24] [стр.25] [стр.26] [стр.27] [стр.28] [стр.29] [стр.30] [стр.31] [стр.32] [стр.33] [стр.34] [стр.35] [стр.36] [стр.37] [стр.38] [стр.39] [стр.40] [стр.41] [стр.42] [стр.43] [стр.44] [стр.45] [стр.46] [стр.47] [стр.48] [стр.49] [стр.50] [стр.51] [стр.52] [стр.53] [стр.54] [стр.55] [стр.56] [стр.57] [стр.58] [стр.59] [стр.60] [стр.61] [стр.62] [стр.63] [стр.64] [стр.65] [стр.66] [стр.67] [стр.68] [стр.69] [стр.70] [стр.71] [стр.72] [стр.73] [стр.74] [стр.75] [стр.76] [стр.77] [стр.78] [стр.79] [стр.80] [стр.81] [стр.82] [стр.83] [стр.84] [стр.85] [стр.86] [стр.87] [стр.88] [стр.89] [стр.90] [стр.91] [стр.92] [стр.93] [стр.94] [стр.95] [стр.96] [стр.97] [стр.98] [стр.99] [стр.100] [стр.101] [стр.102] [стр.103] [стр.104] [стр.105] [стр.106] [стр.107] [стр.108] [стр.109] [стр.110] [стр.111] [стр.112] [стр.113] [стр.114] [стр.115] [стр.116] [стр.117] [стр.118] [стр.119] [стр.120] [стр.121] [стр.122] [стр.123] [стр.124] [стр.125] [стр.126] [стр.127] [стр.128] [стр.129] [стр.130] [стр.131] [стр.132] [стр.133] [стр.134] [стр.135] [стр.136] [стр.137] [стр.138] [стр.139] [стр.140] [стр.141] [стр.142] [стр.143] [стр.144] [стр.145] [стр.146] [стр.147] [стр.148] [стр.149] [стр.150] [стр.151] [стр.152] [стр.153] [стр.154] [стр.155] [стр.156] [стр.157] [стр.158] [стр.159] [стр.160] [стр.161] [стр.162] [стр.163] [стр.164] [стр.165] [стр.166] [стр.167] [стр.168] [стр.169] [стр.170] [стр.171] [стр.172] [стр.173] [стр.174] [стр.175] [стр.176] [стр.177] [стр.178] [стр.179] [стр.180] [стр.181] [стр.182] [стр.183] [стр.184] [стр.185] [стр.186] [стр.187] [стр.188] [стр.189] [стр.190] [стр.191] [стр.192] [стр.193] [стр.194] [стр.195] [стр.196]