Третья функция сильно отличается от второй, так как в ней каждый раз, когда вы делаете вывод, вы вычисляете как значение результата 100 - amount
(параметр функции), тогда как во второй есть начальный баланс,100, и каждый раз, когда вы снимаете деньги, они вычитаются из баланса текущего .
(define new-withdraw
(let ((balance 100))
(lambda (amount) ;;
(if (>= balance amount)
(begin (set! balance (- balance amount))
balance)
"Insufficient funds"))))
> (new-withdraw 40)
;Value: 60
> (new-withdraw 30)
;Value: 30 ; equal to 60 - 30
(define (new-withdraw-2 amount)
(let ((balance 100))
(if (>= balance amount)
(begin (set! balance (- balance amount))
balance)
"Insufficient funds")))
> (new-withdraw-2 40)
;Value: 60
>(new-withdraw-2 30)
;Value: 70 ; equal to 100 - 30
Итак, new-withdraw-2
не моделирует банковский счет, и функцияпросто сложный способ определения f (x) = 100 - x
.
Почему эти две функции так сильно отличаются, даже если на первый взгляд они похожи?
Различие дается семантикой let
: в первом случае в new-withdraw
let
вводит новую переменную balance
, которая устанавливает новую «среду», а затем возвращает новую функцию (внутреннюю lambda
), для которой переменнаяbalance
является внешним. Таким образом, возвращаемая функция, каждый раз, когда она вызывается, обращается к той же самой переменной и уменьшает ее значение. В следующий раз, когда он будет вызван, через ту же самую переменную будет найдено значение, уменьшенное в предыдущем вызове. Такие объекты, как внутренняя функция, называются «замыканиями», поскольку функция и внешняя среда жестко связаны со средой, образующей «скрытое» в функции состояние и сохраняющейся между различными вызовами функции.
Во втором случае вместо этого let
находится внутри функции new-withdraw-2
: это означает, что каждый раз, когда вызывается функция, определяется new переменная balance
, которая устанавливает новыйВ среде, локальной для функции, переменная инициализируется до 100, а затем уменьшается (с set!
). Но когда функция завершается, возвращая новый баланс, локальное окружение функции теряется, и в следующий раз, когда функция будет вызвана, новое окружение будет установлено снова, при этом переменная balance
снова инициализируется равной 100.