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


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




[25]

1.3.4 Процедуры как возвращаемые значения

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

Эту идею можно проиллюстрировать примером с поиском неподвижной точки, обсуждаемым в конце раздела 1.3.3. Мы сформулировали новую версию процедуры вычисления квадратного корня как поиск неподвижной точки, начав с наблюдения, что л/х есть неподвижная точка функции у i-> х/у. Затем мы использовали торможение усреднением, чтобы заставить приближения сходиться. Торможение усреднением само по себе является полезным приемом. А именно, получив функцию f, мы возвращаем функцию, значение которой в точке х есть среднее арифметическое между x и f(x).

Идею торможения усреднением мы можем выразить при помощи следующей процедуры:

(define (average-damp f)

(lambda (x) (average x (f x))))

Average-damp - это процедура, принимающая в качестве аргумента процедуру f и возвращающая в качестве значения процедуру (полученную с помощью lambda), которая, будучи применена к числу x, возвращает среднее между x и (f x) . Например, применение average-damp к процедуре square получает процедуру, значением которой для некоторого числа x будет среднее между x и x2. Применение этой процедуры к числу 10 возвращает среднее между 10 и 100, то есть 55:59

((average-damp square) 10)

55

Используя average-damp, мы можем переформулировать процедуру вычисления квадратного корня следующим образом:

(define (sqrt x)

(fixed-point (average-damp (lambda (y) (/ x y)))

1.0))

Обратите внимание, как такая формулировка делает явными три идеи нашего метода: поиск неподвижной точки, торможение усреднением и функцию y - x/y. Полезно сравнить такую формулировку метода поиска квадратного корня с исходной версией, представленной в разделе 1.1.7. Вспомните, что обе процедуры выражают один и тот же процесс, и посмотрите, насколько яснее становится его идея, когда мы выражаем процесс в терминах этих абстракций. В общем случае существует много способов сформулировать процесс в виде процедуры. Опытные программисты знают, как выбрать те формулировки процедур, которые наиболее ясно выражают их мысли, и где полезные элементы

59Заметьте, что здесь мы имеем комбинацию, оператор которой сам по себе комбинация. В упражнении 1.4 уже была продемонстрирована возможность таких комбинаций, но то был всего лишь игрушечный пример. Здесь мы начинаем чувствовать настоящую потребность в выражениях такого рода - когда нам нужно применить процедуру, полученную в качестве значения из процедуры высшего порядка.


процесса показаны в виде отдельных сущностей, которые можно использовать в других приложениях. Чтобы привести простой пример такого нового использования, заметим, что кубический корень x является неподвижной точкой функции y - x/y2, так что мы можем немедленно обобщить нашу процедуру поиска квадратного корня так, чтобы она извлекала кубические корни:60

(define (cube-root x)

(fixed-point (average-damp (lambda (y) (/ x (square y))))

1.0))

Метод Ньютона

Когда в разделе 1.1.7 мы впервые представили процедуру извлечения квадратного корня, мы упомянули, что это лишь частный случай метода Ньютона (Newthons method). Если x - g(x) есть дифференцируемая функция, то решение уравнения g(x) = 0 есть неподвижная точка функции x - f (x), где

а Dg(x) есть производная g, вычисленная в точке x. Метод Ньютона состоит в том, чтобы применить описанный способ поиска неподвижной точки и аппроксимировать решение уравнения путем поиска неподвижной точки функции f .61 Для многих функций g при достаточно хорошем начальном значении x метод Ньютона очень быстро приводит к решению уравнения g(x) = 0.62

Чтобы реализовать метод Ньютона в виде процедуры, сначала нужно выразить понятие производной. Заметим, что «взятие производной», подобно торможению усреднением, трансформирует одну функцию в другую. Например, производная функции x - x3 есть функция x - 3x2. В общем случае, если g есть функция, а dx - маленькое число, то производная Dg функции g есть функция, значение которой в каждой точке x описывается формулой (при dx, стремящемся к нулю)

Таким образом, мы можем выразить понятие производной (взяв dx равным, например, 0.00001) в виде процедуры

(define (deriv g) (lambda (x)

(/ (- (g (+ x dx)) (g x))

dx)))

дополненной определением

(define dx 0.00001)

60См. дальнейшее обобщение в упражнении 1.45

61 Вводные курсы анализа обычно описывают метод Ньютона через последовательность приближений i„+i = xn - g(xn)/Dg(xn). Наличие языка, на котором мы можем говорить о процессах,

а также использование идеи неподвижных точек, упрощают описание этого метода.

62Метод Ньютона не всегда приводит к решению, но можно показать, что в удачных случаях каждая итерация удваивает точность приближения в терминах количества цифр после запятой. Для таких случаев метод Ньютона сходится гораздо быстрее, чем метод половинного деления.

f(x)

Dg(x)

Dg(x)

g(x + dx) - g(x) dx


Подобно average-damp, deriv является процедурой, которая берет процедуру в качестве аргумента и возвращает процедуру как значение. Например, чтобы найти приближенное значение производной x - x3 в точке 5 (точное значение производной равно 75), можно вычислить

(define (cube x) (* x x x))

((deriv cube) 5) 75.00014999664018

С помощью deriv мы можем выразить метод Ньютона как процесс поиска неподвижной точки:

(define (newton-transform g) (lambda (x)

(- x (/ (g x) ((deriv g) x)))))

(define (newtons-method g guess)

(fixed-point (newton-transform g) guess))

Процедура newton-transform выражает формулу, приведенную в начале этого раздела, а newtons-method легко определяется с ее помощью. В качестве аргументов она принимает процедуру, вычисляющую функцию, чей ноль мы хотим найти, а также начальное значение приближения. Например, чтобы найти квадратный корень x, мы можем с помощью метода Ньютона найти ноль функции y - y2 - x, начиная со значения 1.63 Это дает нам еще одну форму процедуры вычисления квадратного корня:

(define (sqrt x)

(newtons-method (lambda (y) (- (square y) x))

1.0))

Абстракции и процедуры как полноправные объекты

Мы видели два способа представить вычисление квадратного корня как частный случай более общего метода; один раз это был поиск неподвижной точки, другой - метод Ньютона. Поскольку сам метод Ньютона был выражен как процесс поиска неподвижной точки, на самом деле мы увидели два способа вычислить квадратный корень как неподвижную точку. Каждый из этих методов получает некоторую функцию и находит неподвижную точку для некоторой трансформации этой функции. Эту общую идею мы можем выразить как

процедуру:

(define (fixed-point-of-transform g transform guess) (fixed-point (transform g) guess))

Эта очень общая процедура принимает в качестве аргументов процедуру g, которая вычисляет некоторую функцию, процедуру, которая трансформирует g, и начальное приближение. Возвращаемое значение есть неподвижная точка трансформированной функции.

63 При поиске квадратных корней метод Ньютона быстро сходится к правильному решению, начиная с любой точки.



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