【SICP练习】104 练习3.1-3.4

练习3-1

原文

Exercise 3.1. An accumulator is a procedure that is called repeatedly with a single numeric argument and accumulates its arguments into a sum. Each time it is called, it returns the currently accumulated sum. Write a procedure make-accumulator that generates accumulators, each maintaining an independent sum. The input to make-accumulator should specify the initial value of the sum; for example
(define A (make-accumulator 5))
(A 10)
15
(A 10)
25

分析

这道题目并不难,其讲的是一个累加器,其实就和前面的银行余额那个差不多啦。而且比第153页的make-account更简单,这是因为这个函数只需要make-account的deposit一个函数而已。

代码

(define (make-accumulator value)
   (lambda (add-value)
       (set! value (+ value add-value))
       value))

练习3-2

原文

Exercise 3.2. In software-testing applications, it is useful to be able to count the number of times a given procedure is called during the course of a computation. Write a procedure make-monitored that takes as input a procedure, f, that itself takes one input. The result returned by make-monitored is a third procedure, say mf, that keeps track of the number of times it has been called by maintaining an internal counter. If the input to mf is the special symbol how-many-calls?, then mf returns the value of the counter. If the input is the special symbol reset-count, then mf resets the counter to zero. For any other input, mf returns the result of calling f on that input and increments the counter. For instance, we could make a monitored version of the sqrt procedure:
(define s (make-monitored sqrt))
(s 100)
10
(s ‘how-many-calls?)
1

分析

题目后的代码中很好的说明了过程make-monitored的作用,例如其传入参数sqrt后则会返回另一个过程给s。而将100这个参数传给s时则会得到100的sqrt。同时将how-many-calls?传给s,也就意味着将其传入make-monitored,这就是题目中所说的第二个参数。

因此对于make-monitored来说,
1.一个参数f
2.一个内部计数器count-call
3.返回一个过程,并且其有一个输入。
4.如果返回过程的输入为how-many-call?则返回count-call;
如果这个输入为reset-count则对count-call做清零处理;
如果是其他输入则将f应用于这个输入的结果,并将内部计数器加1,例如题目中的(s 10)。

而这段代码的难点在于,
1.一开始要用let将count-call记为0
2.在输入为reset-count的时,用set!将count-call清0
3.在其他情况时,除了用set!做加1处理外,还要同时将f应用于input。

代码

(define (make-monitored f)
  (let ((count-call 0))
    (lambda (input)
      (cond ((eq? input 'how-many-calls?)
         count-call)
        ((eq? input 'reset-count)
         (begin (set! count-call 0)
            count-call))
        (else
         (begin
           (set! count-call (+ 1 count-call))
           (f input)))))))

测试

(define (make-monitored f)
  (let ((count-call 0))
    (lambda (input)
      (cond ((eq? input 'how-many-calls?)
         count-call)
        ((eq? input 'reset-count)
         (begin (set! count-call 0)
            count-call))
        (else
         (begin
           (set! count-call (+ 1 count-call))
           (f input)))))))
;Value: make-monitored

(define (cube x)
  (* x x x))
;Value: cube

(define z (make-monitored cube))
;Value: z

(z 10)
;Value: 1000

(z 10)
;Value: 1000

(z 'how-many-calls?)
;Value: 2

练习3-3

原文

Exercise 3.3. Modify the make-account procedure so that it creates password-protected accounts. That is, make-account should take a symbol as an additional argument, as in
(define acc (make-account 100 ‘secret-password))
The resulting account object should process a request only if it is accompanied by the password with which the account was created, and should otherwise return a complaint:
((acc ‘secret-password ‘withdraw) 40)
60
((acc ‘some-other-password ‘deposit) 50)
“Incorrect password”

分析

相对于153页的make-account函数,这道题要添加
1.判断密码是否正确的谓词correct-password?
2.输出错误信息的函数display-warning-message

另外在测试之后,会发现display-warning-message需要一个参数,即是它并没有用到。否则会有如下错误信息:

;The procedure #[compound-procedure 13 display-warning-message] has been called with 1 argument; it requires exactly 0 arguments.

代码

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

  (define (deposit amount)
    (set! balance (+ balance amount)
    balance)

  (define (correct-password? input-password)
    (eq? password input-password))

  (define (display-warning-message msg)
    (display "Incorrect password"))

  (define (dispatch input-password m)
    (if (correct-password? input-password)
        (cond ((eq? m 'withdraw)
                withdraw)
              ((eq? m 'deposit)
                deposit)
              (else
               (error "Unknow request -- MAKE-ACCOUNT" mode)))
        display-warning-message))

  dispatch)

测试

(define acc (make-account 100 'secret-password))
;Value: acc

((acc 'secret-password 'withdraw) 40)
;Value: 60

((acc 'some-other-password 'deposit) 60)
Incorrect password
;Unspecified return value

练习3-4

原文

Exercise 3.4. Modify the make-account procedure of exercise 3.3 by adding another local state variable so that, if an account is accessed more than seven consecutive times with an incorrect password, it invokes the procedure call-the-cops.

分析

这道题是上一道题的补充,其主要添加了,
1.尝试次数try-times
2.上一题的display-warning-message做修改:用set!将尝试次数try-times加1,大于7次时调用过程call-the-cops

代码

(define (make-account balance password)
    (let ((try-times 0))
      (define (call-the-cops)
          (error "You try too much times, calling the cops ..."))

      (define (withdraw amount)
              (if (>= balance amount)
                  (begin (set! balance (- blance amount))
                         balance)

      (define (deposit amount)
              (set! balance (+ balance amount)))

      (define (correct-password? input-password)                         
              (eq? password input-password))    

      (define (display-warning-message msg)                
              (display "Incorrect password"))                        

      (define (dispatch input-password m)          
              (if (password-match? input-password)                          
                  (begin
                    (set! try-times 0)                    
                    (cond ((eq? m 'withdraw)
                            withdraw)
                          ((eq? m 'deposit)
                            deposit)
                          (else
                            (error "Unknow request -- MAKE-ACCOUNT" mode))))
                  (begin          
                    (set! try-times (+ 1 try-times))      
                    (if (>= try-times 7)
                        (call-the-cops)
                        display-warning-message)))) 
        dispatch))

测试

(define acc (make-count 100 'secret-password))

;Value: acc

((acc 'wrong-password 'withdraw) 10)
Incorrect password
;Unspecified return value

((acc 'wrong-password 'withdraw) 10)
Incorrect password
;Unspecified return value

((acc 'wrong-password 'withdraw) 10)
Incorrect password
;Unspecified return value

((acc 'wrong-password 'withdraw) 10)
Incorrect password
;Unspecified return value

((acc 'wrong-password 'withdraw) 10)
Incorrect password
;Unspecified return value

((acc 'wrong-password 'withdraw) 10)
Incorrect password
;Unspecified return value

((acc 'wrong-password 'withdraw) 10)

;You try too much times, calling the cops ...
;To continue, call RESTART with an option number:
; (RESTART 1) => Return to read-eval-print level 1.



感谢访问,希望对您有所帮助。 欢迎关注或收藏、评论或点赞。


为使本文得到斧正和提问,转载请注明出处:
http://blog.csdn.net/nomasp


版权声明:本文为 NoMasp柯于旺 原创文章,如需转载请联系本人。

posted @ 2015-03-08 17:06  nomasp  阅读(156)  评论(0编辑  收藏  举报