Scheme 使用lambda模拟银行余额提取行为

Scheme 使用lambda模拟银行余额提取行为,scheme,sicp,Scheme,Sicp,我在读书 该解决方案提出了暴露平衡状态的问题,作为解决方案,引入局部变量 (define new-withdraw (let ((balance 100)) (lambda (amount) ;; (if (>= balance amount) (begin (set! balance (- balance amount)) balance) "Insufficient funds"))))

我在读书

该解决方案提出了暴露
平衡
状态的问题,作为解决方案,引入局部变量

(define new-withdraw
  (let ((balance 100))
    (lambda (amount) ;;
      (if (>= balance amount)
          (begin (set! balance (- balance amount))
                 balance)
          "Insufficient funds"))))

> (new-withdraw 40)
;Value: 60
lambda
也被引入,甚至认为它可以被改写为

(define (new-withdraw-2 amount)
  (let ((balance 100))
      (if (>= balance amount)
          (begin (set! balance (- balance amount))
                 balance)
          "Insufficient funds")))

;Value: new-withdraw-2
8 error> (new-withdraw-2 30)
;Value: 70

我认为在这里应用
lambda
似乎没有必要。我遗漏了什么?

第三个函数与第二个函数非常不同,因为在它中,每次进行取款时,都会计算结果值
100-金额(函数的参数),而在第二个函数中,有一个初始余额100,每次进行取款时,它从当前余额中减损

因此,
new-draw-2
并没有为银行账户建模,该函数只是定义
f(x)=100-x
的一种精细方法

为什么这两种功能如此不同,即使它们表面上看起来很相似

不同之处在于
let
的语义:在第一种情况下,在
new draw
中,
let
引入一个新变量
balance
,该变量建立一个新的“环境”,然后返回一个新函数(内部
lambda
),变量
余额
是外部变量。因此,每次调用返回的函数时,都会访问同一个变量并减小其值。下次调用它时,它将通过同一个变量发现上一次调用中减少的值。 内部函数等对象称为“闭包”,因为函数与外部环境是严格连接的,与环境形成一种状态“隐藏”在函数中,并在函数的不同调用之间持久化

相反,在第二种情况下,
let
位于函数
new-draw-2
:这意味着每次调用函数时,都会定义一个新的变量
balance
,它建立了一个新的环境,函数本地的,变量被初始化为100,然后减小(设置
时)
). 但当函数终止并返回新的平衡时,函数的本地环境将丢失,下次调用函数时,将再次建立一个新环境,变量
平衡
再次初始化为100

(define (new-withdraw-2 amount)
  (let ((balance 100))
      (if (>= balance amount)
          (begin (set! balance (- balance amount))
                 balance)
          "Insufficient funds")))

;Value: new-withdraw-2
8 error> (new-withdraw-2 30)
;Value: 70
(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