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


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




[78]

(define (cons x y)

(let ((new (get-new-pair))) (set-car! new x) (set-cdr! new y) new))

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

В разделе 2.2.1 была введена следующая процедура для добавления одного списка к другому:

(define (append x y)

(if (null? x) y

(cons (car x) (append (cdr x) y))))

Append порождает новый список, по очереди наращивая элементы x в начало у. Процедура append! подобна append, но только она является не конструктором, а мутатором. Она склеивает списки вместе, изменяя последнюю пару x так, что ее cdr становится равным у. (Вызов append! с пустым x является ошибкой.)

(define (append! x y)

(set-cdr! (last-pair x) y)

x)

Здесь last-pair - процедура, которая возвращает последнюю пару своего аргумента: (define (last-pair x)

(if (null? (cdr x))

x

(last-pair (cdr x))))

Рассмотрим последовательность действий

(define x (list a b)) (define y (list c d))

(define z (append x у)) z

(a b c d)

(cdr x)

(ответ)

(define w (append! x y)) w

(a b c d)

(cdr x)

( ответ)

Каковы будут пропущенные (ответы)? Объясните, нарисовав стрелочные диаграммы. ления памятью в рамках реализации Лиспа. Мы рассмотрим эти вопросы в разделе 5.3.1.


zi-

471

Рис. 3.16: Список zi, порождаемый выражением (cons x x).

x

b

a

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

Рассмотрим следующую процедуру make-cycle, которая пользуется last-pair из упражнения 3.12:

(define (make-cycle x)

(set-cdr! (last-pair x) x)

x)

Нарисуйте стрелочную диаграмму, которая изображает структуру z, созданную таким кодом:

(define z (make-cycle (list a b c)))

Что случится, если мы попробуем вычислить (last-pair z)?

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

Следующая процедура, хотя и сложна для понимания, вполне может оказаться полезной:

(define (mystery x) (define (loop x y) (if (null? x)

y

(let ((temp (cdr x))) (set-cdr! x y) (loop temp x))))

(loop x ()))

Loop пользуется «временной» переменной temp, чтобы сохранить старое значение cdr пары x, поскольку set-cdr! на следующей строке его разрушает. Объясните, что за задачу выполняет mystery. Предположим, что переменная v определена выражением (define v (list a b c d). Нарисуйте диаграмму, которая изображает список, являющийся значением v. Допустим, что теперь мы выполняем (define w (mystery v)) . Нарисуйте стрелочные диаграммы, которые показывают структуры v и w после вычисления этого выражения. Что будет напечатано в качестве значений v и

w?

Разделение данных и их идентичность

В разделе 3.1.3 мы упоминали теоретические вопросы «идентичности» и «изменения», которые возникают с появлением присваивания. Эти вопросы начинают иметь практическое значение тогда, когда отдельные пары разделяются (are shared) между различными объектами данных. Рассмотрим, например, структуру, которая создается таким кодом:


43

b

Рис. 3.17: Список z2, порождаемый выражением (cons (list a b) (list a b)).

x

a

(define x (list a b)) (define zl (cons x x))

Как показано на рис. 3.16, zl представляет собой пару, в которой car и cdr указывают на одну и ту же пару x. Разделение x между car и cdr пары z1 возникает оттого, что cons реализован простейшим способом. В общем случае построение списков с помощью cons приводит к возникновению сложносвязан-ной сети пар, в которой многие пары разделяются между многими различными структурами.

В противоположность рис. 3.16, рис. 3.17 показывает структуру, которая порождается кодом

(define z2 (cons (list a b) (list a b)))

В этой структуре пары двух списков (a b) различны, притом, что сами символы разделяются.14

Если мы рассматриваем zl и z2 как списки, они представляют «один и тот же» список ((a b) a b). Вообще говоря, разделение данных невозможно заметить, если мы работаем со списками только при помощи операций cons, car и cdr. Однако если мы вводим мутаторы, работающие со списковой структурой, разделение данных начинает иметь значение. Как пример случая, когда разделение влияет на результат, рассмотрим следующую процедуру, которая изменяет car структуры, к которой она применяется:

(define (set-to-wow! x) (set-car! (car x) wow)

x)

Несмотря на то, что zl и z2 имеют «одинаковую» структуру, применение к ним процедуры set-to-wow! дает различные результаты. В случае с zl изменение car влияет и на cdr, поскольку здесь car и cdr - это одна и та же пара. В случае с z2, car и cdr различны, так что set-to-wow! изменяет только car:

19Пары различаются потому, что каждый вызов cons порождает новую пару. Символы разделяются; в Scheme существует только один символ для каждого данного имени. Поскольку Scheme не дает возможности изменять символ, это разделение невозможно заметить. Заметим, кроме того, что именно разделение позволяет нам сравнивать символы при помощи eq?, который просто проверяет равенство указателей.



[стр.Начало] [стр.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]