使用 lambda 模拟银行余额提取行为
Simulate a bank balance withdraw behavior with lambda
我正在阅读3.1 Assignment and Local State of SICP
(define balance 100)
(define (withdraw amount)
(if (>= balance amount)
(begin (set! balance (- balance amount))
balance) ;
"Insufficient funds"))
;Value: balance
1 ]=>
;Value: withdraw
1 ]=> (withdraw 50)
;Value: 50
1 ]=> (withdraw 30)
;Value: 20
该方案存在暴露balance
状态的问题,作为解决方案,引入局部变量
(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 - 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
,它建立了一个新的“环境”,然后 return 一个新函数(内部 lambda
),变量 balance
是外部的。因此,每次调用 returned 函数时,都会访问 same 变量并减少其值。下次调用时,会发现,通过same变量,上次调用时的值变小了。
函数内部等对象被称为“闭包”,因为函数与外部环境是严格相连的,环境在函数中形成一种“隐藏”的状态,并在函数的不同调用之间持久存在。
在第二种情况下,let
位于函数 new-withdraw-2
内:这意味着每次调用该函数时,一个 new变量 balance
被定义,它建立了一个新的环境,局部于函数,变量被初始化为 100,然后它被减少(set!
)。但是当函数终止,returning new balance,函数的本地环境就丢失了,下次调用函数时会重新建立新的环境,变量balance
再次初始化为 100.
我正在阅读3.1 Assignment and Local State of SICP
(define balance 100)
(define (withdraw amount)
(if (>= balance amount)
(begin (set! balance (- balance amount))
balance) ;
"Insufficient funds"))
;Value: balance
1 ]=>
;Value: withdraw
1 ]=> (withdraw 50)
;Value: 50
1 ]=> (withdraw 30)
;Value: 20
该方案存在暴露balance
状态的问题,作为解决方案,引入局部变量
(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 - 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
,它建立了一个新的“环境”,然后 return 一个新函数(内部 lambda
),变量 balance
是外部的。因此,每次调用 returned 函数时,都会访问 same 变量并减少其值。下次调用时,会发现,通过same变量,上次调用时的值变小了。
函数内部等对象被称为“闭包”,因为函数与外部环境是严格相连的,环境在函数中形成一种“隐藏”的状态,并在函数的不同调用之间持久存在。
在第二种情况下,let
位于函数 new-withdraw-2
内:这意味着每次调用该函数时,一个 new变量 balance
被定义,它建立了一个新的环境,局部于函数,变量被初始化为 100,然后它被减少(set!
)。但是当函数终止,returning new balance,函数的本地环境就丢失了,下次调用函数时会重新建立新的环境,变量balance
再次初始化为 100.