Главная » Просмотр файлов » Х. Абельсон, Дж. Дж. Сассман, Дж. Сассман - Структура и интерпретация компьютерных программ

Х. Абельсон, Дж. Дж. Сассман, Дж. Сассман - Структура и интерпретация компьютерных программ (1108516), страница 51

Файл №1108516 Х. Абельсон, Дж. Дж. Сассман, Дж. Сассман - Структура и интерпретация компьютерных программ (Х. Абельсон, Дж. Дж. Сассман, Дж. Сассман - Структура и интерпретация компьютерных программ) 51 страницаХ. Абельсон, Дж. Дж. Сассман, Дж. Сассман - Структура и интерпретация компьютерных программ (1108516) страница 512019-04-28СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 51)

Воспользуемся для этого процедурой withdraw, которая в качествеаргумента принимает сумму, которую требуется снять. Если на счету имеется достаточно средств, чтобы осуществить операцию, то withdraw возвращает баланс, остающийсяпосле снятия. В противном случае withdraw возвращает сообщение «Недостаточно денег на счете». Например, если вначале на счету содержится 100 долларов, мы получимследующую последовательность результатов:(withdraw 25)75(withdraw 25)50(withdraw 60)"Недостаточно денег на счете"(withdraw 15)35Обратите внимание, что выражение (withdraw 25), будучи вычислено дважды, дает различные результаты.

Это новый тип поведения для процедуры. До сих пор все нашипроцедуры можно было рассматривать как описания способов вычисления математических функций. Вызов процедуры вычислял значение функции для данных аргументов, идва вызова одной и той же процедуры с одинаковыми аргументами всегда приводили кодинаковому результату1 .При реализации withdraw мы используем переменную balance, которая показывает остаток денег на счете, и определяем withdraw в виде процедуры, которая обращается к этой переменной.

Процедура withdraw проверяет, что значение balance неменьше, чем значение аргумента amount. Если это так, withdraw уменьшает значение balance на amount и возвращает новое значение balance. В противном случаеона возвращает сообщение «Недостаточно денег на счете». Вот определения balance иwithdraw:(define balance 100)(define (withdraw amount)(if (>= balance amount)(begin (set! balance (- balance amount))balance)"Недостаточно денег на счете"))1 На самом деле это не совсем правда. Одно исключение — генератор случайных чисел из раздела 1.2.6.Второе связано с таблицами операций и типов, которые мы ввели в разделе 2.4.3, где значения двух вызововget с одними и теми же аргументами зависели от того, какие были в промежутке между ними вызовы put. Сдругой стороны, пока мы не ввели присваивание, мы лишены возможности самим создавать такие процедуры.214Глава 3. Модульность, объекты и состояниеЗначение переменной balance уменьшается, когда мы выполняем выражение(set! balance (- balance amount))Здесь используется особая форма set!, синтаксис которой выглядит так:(set! hимяi hновое-значениеi)Здесь hимяi — символ, а hновое-значениеi – произвольное выражение.

Set! заменяет значение hимениi на результат, полученный при вычислении hнового-значенияi. Вданном случае, мы изменяем balance так, что его новое значение будет результатомвычитания amount из предыдущего значения balance2 .Кроме того, withdraw использует особую форму begin, когда проверка if выдаетистину, и требуется вычислить два выражения: сначала уменьшить balance, а затемвернуть его значение. В общем случае вычисление выражения(begin hвыражение1i hвыражение2i ... hвыражениеk i)приводит к последовательному вычислению выражений от hвыражения1i до hвыраженияki,и значение последнего выражения hвыражениеk i возвращается в качестве значения всейформы begin3 .Хотя процедура withdraw и работает так, как мы того хотели, переменная balanceпредставляет собой проблему.

Balance, как она описана выше, является переменной,определенной в глобальном окружении, и любая процедура может прочитать или изменить ее значение. Намного лучше было бы, если бы balance можно было сделатьвнутренней переменной для withdraw, так, чтобы только withdraw имела доступ кней напрямую, а любая другая процедура — только посредством вызовов withdraw.Так можно будет более точно смоделировать представление о balance как о внутренней переменной состояния, с помощью которой withdraw следит за состоянием счета.Сделать balance внутренней по отношению к withdraw мы можем, переписав определение следующим образом:(define new-withdraw(let ((balance 100))(lambda (amount)(if (>= balance amount)(begin (set! balance (- balance amount))balance)"Недостаточно денег на счете"))))Здесь мы, используя let, создаем окружение с внутренней переменной balance, которой вначале присваивается значение 100. Внутри этого локального окружения мы при2 Значение выражения set! зависит от реализации.

Set! нужно использовать только ради эффекта, который оно оказывает, а не ради значения, которое оно возвращает.Имя set! отражает соглашение, принятое в Scheme: операциям, которые изменяют значения переменных(или структуры данных, как мы увидим в разделе 3.3) даются имена с восклицательным знаком на конце.

Этонапоминает соглашение называть предикаты именами, которые оканчиваются на вопросительный знак.3 Неявно мы уже использовали в своих программах begin, поскольку в Scheme тело процедуры может бытьпоследовательностью выражений. Кроме того, в каждом подвыражении cond следствие может состоять не изодного выражения, а из нескольких.3.1. Присваивание и внутреннее состояние объектов215помощи lambda определяем процедуру, которая берет в качестве аргумента amount идействует так же, как наша старая процедура withdraw.

Эта процедура — возвращаемая как результат выражения let, — и есть new-withdraw. Она ведет себя в точноститак же, как, как withdraw, но ее переменная balance недоступна для всех остальныхпроцедур4 .Set! в сочетании с локальными переменными — общая стратегия программирования,которую мы будем использовать для построения вычислительных объектов, обладающихвнутренним состоянием. К сожалению, при использовании этой стратегии возникаетсерьезная проблема: когда мы только вводили понятие процедуры, мы ввели также подстановочную модель вычислений (раздел 1.1.5) для того, чтобы объяснить, что означаетприменение процедуры к аргументам. Мы сказали, что оно должно интерпретироватьсякак вычисление тела процедуры, в котором формальные параметры заменяются на своизначения.

К сожалению, как только мы вводим в язык присваивание, подстановка перестает быть адекватной моделью применения процедуры. (Почему это так, мы поймем вразделе 3.1.3.) В результате, с технической точки зрения мы сейчас не умеем объяснить,почему процедура new-withdraw ведет себя именно так, как описано выше. Чтобыдействительно понять процедуры, подобные new-withdraw, нам придется разработатьновую модель применения процедуры. В разделе 3.2 мы введем такую модель, попутно объяснив set! и локальные переменные. Однако сначала мы рассмотрим некоторыевариации на тему, заданную new-withdraw.Следующая процедура, make-withdraw, создает «обработчики снятия денег со счетов». Формальный параметр balance, передаваемый в make-withdraw, указывает начальную сумму денег на счету5 .(define (make-withdraw balance)(lambda (amount)(if (>= balance amount)(begin (set! balance (- balance amount))balance)"Недостаточно денег на счете")))При помощи make-withdraw можно следующим образом создать два объекта W1 и W2:(define W1 (make-withdraw 100))(define W2 (make-withdraw 100))(W1 50)50(W2 70)304 По терминологии, принятой при описании языков программирования, переменная balance инкапсулируется (is encapsulated) внутри процедуры new-withdraw.

Инкапсуляция отражает общий принцип проектирования систем, известный как принцип сокрытия (the hiding principle): систему можно сделать более модульнойи надежной, если защищать ее части друг от друга; то есть, разрешать доступ к информации только тем частямсистемы, которым «необходимо это знать».5 В отличие от предыдущей процедуры new-withdraw, здесь нам необязательно использовать let, чтобысделать balance локальной переменной, поскольку формальные параметры и так локальны.

Это станет яснеепосле обсуждения модели вычисления с окружениями в разделе 3.2. (См. также упражнение 3.10.)216Глава 3. Модульность, объекты и состояние(W2 40)"Недостаточно денег на счете"(W1 40)10Обратите внимание, что W1 и W2 — полностью независимые объекты, каждый со своейлокальной переменной balance. Снятие денег с одного счета не влияет на другой.Мы можем создавать объекты, которые будут разрешать не только снятие денег, но иих занесение на счет, и таким образом можно смоделировать простые банковские счета.Вот процедура, которая возвращает объект-«банковский счет» с указанным начальнымбалансом:(define (make-account balance)(define (withdraw amount)(if (>= balance amount)(begin (set! balance (- balance amount))balance)"Недостаточно денег на счете"))(define (deposit amount)(set! balance (+ balance amount))balance)(define (dispatch m)(cond ((eq? m ’withdraw) withdraw)((eq? m ’deposit) deposit)(else (error "Неизвестный вызов -- MAKE-ACCOUNT"m))))dispatch)Каждый вызов make-account создает окружение с локальной переменной состоянияbalance.

Внутри этого окружения make-account определяет процедуры depositи withdraw, которые обращаются к balance, а также дополнительную процедуруdispatch, которая принимает «сообщение» в качестве ввода, и возвращает одну издвух локальных процедур. Сама процедура dispatch возвращается как значение, которое представляет объект-банковский счет. Это не что иное, как стиль программированияс передачей сообщений (message passing), который мы видели в разделе 2.4.3, но толькоздесь мы его используем в сочетании с возможностью изменять локальные переменные.Make-account можно использовать следующим образом:(define acc (make-account 100))((acc ’withdraw) 50)50((acc ’withdraw) 60)"Недостаточно денег на счете"((acc ’deposit) 40)3.1.

Присваивание и внутреннее состояние объектов21790((acc ’withdraw) 60)30Каждый вызов acc возвращает локально определенную процедуру deposit или withdraw,которая затем применяется к указанной сумме. Точно так же, как это было с makewithdraw, второй вызов make-account(define acc2 (make-account 100))создает совершенно отдельный объект-счет, который поддерживает свою собственнуюпеременную balance.Упражнение 3.1.Накопитель (accumulator) — это процедура, которая вызывается с одним численным аргументоми собирает свои аргументы в сумму.

При каждом вызове накопитель возвращает сумму, которуюуспел накопить. Напишите процедуру make-accumulator, порождающую накопители, каждыйиз которых поддерживает свою отдельную сумму. Входной параметр make-accumulator долженуказывать начальное значение суммы; например,(define A (make-accumulator 5))(A 10)15(A 10)25Упражнение 3.2.При тестировании программ удобно иметь возможность подсчитывать, сколько раз за время вычислений была вызвана та или иная процедура. Напишите процедуру make-monitored, принимающую в качестве параметра процедуру f, которая сама по себе принимает один входнойпараметр. Результат, возвращаемый make-monitored — третья процедура, назовем ее mf, которая подсчитывает, сколько раз она была вызвана, при помощи внутреннего счетчика. Если навходе mf получает специальный символ how-many-calls?, она возвращает значение счетчика.Если же на вход подается специальный символ reset-count, mf обнуляет счетчик. Для любогодругого параметра mf возвращает результат вызова f с этим параметром и увеличивает счетчик.Например, можно было бы сделать отслеживаемую версию процедуры sqrt:(define s (make-monitored sqrt))(s 100)10(s ’how-many-calls?)1Упражнение 3.3.Измените процедуру make-account так, чтобы она создавала счета, защищенные паролем.А именно, make-account должна в качестве дополнительного аргумента принимать символ,например218Глава 3.

Характеристики

Список файлов книги

Свежие статьи
Популярно сейчас
Почему делать на заказ в разы дороже, чем купить готовую учебную работу на СтудИзбе? Наши учебные работы продаются каждый год, тогда как большинство заказов выполняются с нуля. Найдите подходящий учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
6418
Авторов
на СтудИзбе
307
Средний доход
с одного платного файла
Обучение Подробнее