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


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




[22]

Accumulate принимает в качестве аргументов те же описания термов и диапазона, что и sum с product, а еще процедуру combiner (двух аргументов), которая указывает, как нужно присоединить текущий терм к результату накопления предыдущих, и null-value, базовое значение, которое нужно использовать, когда термы закончатся. Напишите accumulate и покажите, как и sum, и product можно определить в виде простых вызовов accumulate.

b. Если Ваша процедура accumulate порождает рекурсивный процесс, перепишите ее так, чтобы она порождала итеративный. Если она порождает итеративный процесс, перепишите ее так, чтобы она порождала рекурсивный.

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

Можно получить еще более общую версию accumulate (упражнение 1.32), если ввести понятие фильтра (filter) на комбинируемые термы. То есть комбинировать только те термы, порожденные из значений диапазона, которые удовлетворяют указанному условию. Получающаяся абстракция filtered-accumulate получает те же аргументы, что и accumulate, плюс дополнительный одноаргументный предикат, который определяет фильтр. Запишите filtered-accumulate в виде процедуры. Покажите, как с помощью filtered-accumulate выразить следующее:

a.сумму квадратов простых чисел в интервале от a до b (в предположении, что процедура prime? уже написана);

b.произведение всех положительных целых чисел меньше n, которые просты по отношению к n (то есть всех таких положительных целых чисел i < n, что НОД(г, n) = 1).

1.3.2 Построение процедур с помощью lambda

Когда в разделе 1.3.1 мы использовали sum, очень неудобно было определять тривиальные процедуры вроде pi-term и pi-next только ради того, чтобы передать их как аргументы в процедуры высшего порядка. Было бы проще вместо того, чтобы вводить имена pi-next и pi-term, прямо определить «процедуру, которая возвращает свой аргумент плюс 4» и «процедуру, которая вычисляет число, обратное произведению аргумента и аргумента плюс 2». Это можно сделать, введя особую форму lambda, которая создает процедуры. С использованием lambda мы можем записать требуемое в таком виде:

(lambda (x) (+ x 4))

и

(lambda (x) (/ 1.0 (* x (+ x 2))))

Тогда нашу процедуру pi-sum можно выразить безо всяких вспомогательных

процедур:

(define (pi-sum a b)

(sum (lambda (x) (/ 1.0 (* x (+ x 2))))

a

(lambda (x) (+ x 4))

b))

Еще с помощью lambda мы можем записать процедуру integral, не определяя вспомогательную процедуру add-dx:


(define (integral f a b dx) (* (sum f

(+ a (/ dx 2.0)) (lambda (x) (+ x dx))

b)

dx))

В общем случае, lambda используется для создания процедур точно так же, как define, только никакого имени для процедуры не указывается:

(lambda ((формальные-параметры)) (тело))

Получается столь же полноценная процедура, как и с помощью define. Единственная разница состоит в том, что она не связана ни с каким именем в окружении. На самом деле

(define (plus4 x) (+ x 4))

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

(define plus4 (lambda (x) (+ x 4))) Можно читать выражение lambda так:

(lambda(x)(+x4))

Процедура от аргумента x, которая складывает x и 4

Подобно любому выражению, значением которого является процедура, выражение с lambda можно использовать как оператор в комбинации, например

((lambda (x y z) (+ x y (square z))) 1 2 3) 12

Или, в более общем случае, в любом контексте, где обычно используется имя

53

процедуры.53

Создание локальных переменных с помощью let

Еще одно применение lambda состоит во введении локальных переменных. Часто нам в процедуре бывают нужны локальные переменные помимо тех, что связаны формальными параметрами. Допустим, например, что нам надо вычислить функцию

f (x, y) = x(1 + xy)3 + y(1 - y) + (1 + xy)(1 - y) которую мы также могли бы выразить как

53Было бы более понятно и менее страшно для изучающих Лисп, если бы здесь использовалось более ясное имя, чем lambda, например make-procedure. Однако традиция уже прочно укоренилась. Эта нотация заимствована из А-исчисления, формализма, изобретенного математическим логиком Алонсо Чёрчем (Church 1941). Чёрч разработал А-исчисление, чтобы найти строгое основание для понятий функции и применения функции. А-исчисление стало основным инструментом математических исследований по семантике языков программирования.


b

f (x,y)

а

1 + xy 1 - У

ха2 + yb + аЬ

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

(define (f x y)

(define (f-helper a b) (+ (* x (square a))

(* y b) (* a b))) (f-helper (+ 1 (* x y)) (- 1 y)))

Разумеется, безымянную процедуру для связывания локальных переменных мы можем записать через lambda-выражение. При этом тело f оказывается просто вызовом этой процедуры.

(define (f x y) ((lambda (a b)

(+ (* x (square a))

(* y b) (* a b)))

(+ 1 (* x y))

(- 1 y)))

Такая конструкция настолько полезна, что есть особая форма под названием let, которая делает ее более удобной. С использованием let процедуру f можно записать так:

(define (f x y)

(let ((a (+ 1 (* x y)))

(b (- 1 y))) (+ (* x (square a))

(* y b) (* a b))))

Общая форма выражения с let такова:

(let (((nepi) (выр1)) ({nep2) (выр2))

((nepn) (вырп))) (тело))

Это можно понимать как

Пусть (пер1) имеет значение (вг и (пер2) имеет значение (выр)

и (перп) имеет значение (вырп) в (теле)



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