Scheme/Tutorial/6
12 локальные переменные (продолжение)
Продолжаем неустанно совершенствоваться в Scheme. Вы уже видели в предыдущий раз, что локальные переменные можно объявлять в теле функции, пользуясь тем же самым define:
(define (func) (define a 5) (+ a 3))
Однако есть ещё несколько интересных и полезных приёмов работы. Воспользуемся тем, что параметры функции — по сути те же локальные переменные. Тогда пример выше можно было бы сделать следующим образом:
(define (func) ((lambda (a) (+ a 3)) 5))
Попробуем понять, что же произошло. Мы создали функцию с параметром, который назвали a, поместили в неё всё, что нам необходимо — и после этого запустили её, придав параметру требуемое значение 5. Всё, как говорится, гениальное просто. Попробуем ещё, вместо:
(define x 5) (define y 6) (write x) (+ x (* x y))
мы можем написать:
((lambda (x y) (write x) (+ x (* x y))) 5 6)
Данный приём настолько популярен, что имеет общепринятое сокращение — let. Приведённые выражения в сокращённом виде записываются так:
(define (func) (let ((a 5)) (+ a 3)))
(let ((x 5) (y 6)) (write x) (+ x (* x y)))
Если немного поразмышлять, то мы получили не просто способ объявления локальных переменных, а возможность делать блоки с локальными переменными в произвольном месте кода, например:
(define a 3) (write a) ; будет напечатано 3 (let ((a 5)) (write a)) ; будет напечатано 5 (write a) ; будет напечатано 3
У этого приёма есть один существенный недостаток: поскольку формальные параметры инициализируются независимо друг от друга и в неопределённом порядке, мы не можем использовать одни из них для инициализации других; например, в примере с двумя параметрами нельзя у задать равным x.
Но против лома всегда есть другой лом.
Применим одну маленькую хитрость — будем связывать переменные по очереди:
(let ((x 3)) (let ((y x)) .....
Тогда всё получится, на момент определения y, x уже известен и проинициализирован. Этот приём тоже очень распространён, а потому тоже имеет общепринятое сокращение — let*.
(let* ((x 3) (y x)) .....