《SICP中make-account冗余balance表达式作用及多实现差异问询》
SICP与Scheme账户操作相关问题解答
问题1:SICP中make-account的withdraw和deposit里的balance求值表达式作用是什么?
- 在Scheme中,
begin表达式的返回值是其最后一个子表达式的值,而过程的返回值就是其体中最后一个表达式的值。 withdraw和deposit作为对外提供的操作过程,需要返回操作后的账户余额(或者"Insufficient funds"错误信息)。那个看似无用的balance正是整个过程的返回值,供调用者获取操作后的账户状态。比如调用((a1 'withdraw) 20)时,这个表达式的结果就是更新后的余额,而非仅完成扣款操作。
问题2:DrRacket中调用exchange后,withdraw的balance未打印,deposit的balance打印出100的原因?
- DrRacket的交互式环境(REPL)只会自动打印顶层表达式的最终返回值。
- 查看
exchange过程定义,它的体是一个let表达式,最后一个子表达式是((account2 'deposit) difference)——也就是deposit操作的调用。这个调用的返回值(操作后的余额100)就是整个exchange表达式的返回值,因此被REPL自动打印。 - 前面的
((account1 'withdraw) difference)虽执行并返回了更新后的余额,但它不是exchange过程体的最后一个表达式,其返回值未被作为顶层表达式的结果输出,所以只有display的字符串被打印,余额值不会自动输出。
问题3:Chicken Scheme和MIT Scheme中withdraw与deposit的balance打印行为不一致的解释?
- 这是不同Scheme实现的REPL行为差异导致的。Scheme标准并未强制规定REPL必须如何处理非顶层表达式的返回值:
- 部分实现的REPL只会打印顶层表达式的最终返回值(类似DrRacket);
- 另一些实现的REPL会打印过程中所有被求值的表达式的返回值;
- 还有的实现可能对未绑定到变量的表达式返回值做不同处理。
- Chicken Scheme和MIT Scheme的REPL遵循了不同的输出策略,因此导致
withdraw和deposit的返回值(balance)是否被打印出现差异。
附带代码
#lang racket (define (make-account balance) (define (withdraw amount) (if (>= balance amount) (begin (set! balance (- balance amount)) (display "withdraw:\n") balance) "Insufficient funds")) (define (deposit amount) (set! balance (+ balance amount)) (display "deposit:\n") balance) (define (dispatch m) (cond ((eq? m 'deposit) deposit) ((eq? m 'withdraw) withdraw) ((eq? m 'balance) balance) (else (error "Unknown request: MAKE-ACCOUNT" m)))) dispatch) (define (exchange account1 account2) (let ((difference (- (account1 'balance) (account2 'balance)))) ((account1 'withdraw) difference) ((account2 'deposit) difference))) (define a1 (make-account 100)) (define a2 (make-account 75)) (exchange a1 a2)
DrRacket输出示例
withdraw: deposit: 100
内容的提问来源于stack exchange,提问作者musthero
相关产品推荐
相关产品推荐

