Решение упражнения 1.44 из SICP
Это просто замечательнейшее упражнение! Сейчас объясню, почему оно мне так понравилось, но начнем с простого, то есть с определения процедуры smooth. Здесь все достаточно легко:
(define (smooth f dx)
(define (average x y z) (/ (+ x y z) 3))
(lambda (x) (average (f (- x dx))
(f x)
(f (+ x dx)))))
А вот теперь часть похитрее - многократное сглаживание. Приведу первое решение, которое пришло мне в голову:
(define (smooth-n f dx n) (repeated (smooth f dx) n))
Оно хорошо краткостью своей записи, но неверно по сути. Правильное же решение записывается следующим образом:
(define (smooth-n f dx n) ((repeated (lambda (g) (smooth g dx)) n) f))
В чем разница (помимо более длинной записи)? Давайте разберемся.
Может показаться, что эти две записи эквивалентны, но это не так. Отличие в вызове процедуры smooth:
(smooth f dx) против (lambda (g) (smooth g dx))
Я хочу подчеркнуть, что (smooth f dx) - это процедура, которая принимает число и возвращает число. А вот (lambda (g) (smooth g dx)) - это процедура, которая принимает процедуру одного числового аргумента и возвращает также процедуру одного числового аргумента. Прочувствуйте отличие:
- число на входе и число на выходе;
- процедура на входе и процедура на выходе.
Прочитаем первый вариант реализации: применяем однократно сглаженную функцию f последовательно n раз к своему же результату (то есть функцию f’(f’(…f’(x)…)), где f’ - это сглаженная f); получаем функцию числового аргумента. То, что надо? Не похоже…
Второй вариант реализации smooth-n читается таким образом: к функции f применяем преобразование, получающееся в результате применения сглаживания n раз; в результате получаем функцию числового аргумента. Оно? Оно!
Это может показаться не очень простым в понимании. Рекомендую в таком случае попробовать вычислить
((smooth-n square 0.5 2) 1.0)
вручную и программно двумя способами и осознать, почему результаты двух описанных выше процедур smooth-n различны. И добро пожаловать в комментарии.
Comments
Comment from Sergey Khenkin
Date: January 12, 2008, 2:00 pm
Если превратить определение dx из параметра процедур smooth и smooth-n в константу, то код существенно упростится и примет такой вид:
(define (smooth-n f n) ((repeated smooth n) f))
Comment from vladimir
Date: November 8, 2011, 7:10 am
ошибка из за невнимательности и долгие часы мучений.
спасибо за сайт, а то еще долго бы думал ![]()
Write a comment