关于“帧作为本地状态的存储库”

About "Frames as Repository of Local State"

提问人:Enlico 提问时间:1/17/2022 更新时间:1/19/2022 访问量:54

问:

SICP,第 3.2.3 节中的练习 3.10 显示了以下内容作为先前定义的替代方法:make-withdraw

(define (make-withdraw initial-amount)
  (let ((balance initial-amount))
    (lambda (amount)
      (if (>= balance amount)
          (begin (set! balance (- balance amount))
                 balance)
          "Insufficient funds"))))

并规定我们

使用环境模型来分析这个替代版本,绘制如上图所示的图形来说明交互make-withdraw

(define W1 (make-withdraw 100))
(W1 50)
(define W2 (make-withdraw 100))

但是,在上述请求之前,文本回顾了 .(let ((<var> <exp>)) <body>)((lambda (<var>) <body>) <exp>)

现在我想这个建议意味着我应该分析这个版本的:make-withdraw

(define (make-withdraw initial-amount)
  ((lambda (balance)
     (lambda (amount)
       (if (>= balance amount)
         (begin (set! balance (- balance amount))
                balance)
         "Insufficient funds")))
   initial-amount))

或者,甚至更好(基于第 3.2.1 节的过程定义语法只是底层隐式 lambda 表达式的语法糖):

(define make-withdraw
  (lambda (initial-amount)
    ((lambda (balance)
       (lambda (amount)
         (if (>= balance amount)
           (begin (set! balance (- balance amount))
                  balance)
           "Insufficient funds")))
     initial-amount)))

在这里,我看到了 3 个 lambda 过程,而在这个和这个解决方案中(非官方的;我不知道官方解决方案)只显示了两个程序。例如,这是后一种解决方案:

; After (define W1 (make-withdraw 100))
 global env
------------------
|                |<--- env: global env
|                |     parameters: initial-amount
| make-withdraw: ----> body:
|                |       ((lambda (balance)
|                |          (lambda (amount)
|                |            (if (>= balance amount)
|                |                (begin (set! balance (- balance amount))
|                |                       balance)
|                |                "Insufficient funds"))) initial-amount)
|                |
|                |       E1
|                |     -----------------------
|                |<----| initial-amount: 100 |
|                |     -----------------------
|                |          /\
|                |       E2 |
|                |     ----------------
|                |     | balance: 100 |
|                |     ----------------
|                |          /\
|                |          |
|                |     env: E2
|                |     parameters: amount
| W1: ---------------> body:
|                |       (if (>= balance amount)
|                |           (begin (set! balance (- balance amount))
|                |                  balance)
|                |           "Insufficient funds")
------------------

而我本来会想象一个带有 和 的过程也被绘制出来,因为这是(临时的?)lambda,它运行(绑定到 ,而不是 ,而 又绑定到 in)以生成最终绑定到的过程。parameters: balancebody: (lambda (amount) …)E2balanceinitial-amount100100E1W1

我说得对吗?如果没有,你能解释一下原因吗?

函数编程 闭包 方案 状态 SICP

评论


答:

0赞 ignis volens 1/19/2022 #1

当被调用时,它会构造一个绑定到的环境(如图所示)。然后,它立即调用此环境中的另一个函数:该函数构造一个子环境,该子环境绑定到图中的 ,并返回在该环境中定义的第三个函数,因此该函数是 的返回值。(make-withdraw 100)initial-amount100E1balance100E2make-withdraw

所以现在绑定到第三个函数,其环境是 。构造的第二个函数已被调用并返回其值(第三个函数):它不再出现在图片中。W1E2E2

这就是为什么它不再存在的原因。


我不确定它是否有帮助,但如果根本不存在,那么考虑环境图片可能会很有用,因为它实际上只是在点上定义的虚假噪声(显然不是在现实生活中,您可能想做几个帐户!make-withdrawW1

(define W1 ((λ (initial-amount)
              ;; this function was `make-withdraw`
              ((λ (balance)
                 ;; this function was `let`
                 (λ (amount)
                   ;; this is what W1 will end up being
                   (if (>= balance amount)
                       (begin
                         (set! balance (- balance amount))
                         balance)
                       "Insufficient funds")))
               initial-amount))
            100))