sicp-ex-3.2



<< Previous exercise (3.1) | Index | Next exercise (3.3) >>


Igor Saprykin

Not quite according to the task (no mf procedure), but it works.

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

This is wrong, because different procedures returned by make-monitored share the same count.

 > (define s (make-monitored sqrt)) 
 > (s 100) 
 10 
 > (s 'how-many-calls?) 
 1 
 > (define s1 (make-monitored (lambda (x) (* x x)))) 
 > (s1 4) 
 16 
 > (s1 'how-many-calls?) 
 2   # This should be 1.  

The key problem is that count is local to make-monitored instead of (make-monitored f). If we extract (lambda (f) ...) out to use (define (make-monitored f) ...), then all work fine.

---

My implementation is based on 3.1 which is almost same as Daniel-Amariei's.




pluies

A cleaner way, creating mf as suggested, in message-passing style:

  
 (define (make-monitored function) 
   (define times-called 0) 
   (define (mf message) 
     (cond ((eq? message 'how-many-calls?) times-called) 
           ((eq? message 'reset-count) (set! times-called 0)) 
           (else (set! times-called (+ times-called 1)) 
                 (function message)))) 
   mf) 

mvladic

This solution allows to monitor procedures that accepts multiple arguments:

  
 (define (make-monitored proc) 
   (let ((count 0)) 
     (lambda (first . rest) 
       (cond ((eq? first 'how-many-calls?) count) 
             ((eq? first 'reset-count) (set! count 0)) 
             (else (begin (set! count (+ count 1))  
                          (apply proc (cons first rest)))))))) 

Example:

 (define m+ (make-monitored +)) 
 (m+ 40 2) 
 42 
 (m+ 'how-many-calls?) 
 1 

flamingo

Without mf procedure, using lambda:

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

Example:

 (define s (make-monitored sqrt)) 
  
 (s 100) 
 10 
 (s 100) 
 10 
 (s 'how-many-calls?) 
 2 
 >>> 

Daniel-Amariei

  
  
  
 (define (make-accumulator acc) 
   (lambda (x)  
     (set! acc (+ acc x)) 
     acc)) 
  
  
 (define (make-monitored f) 
   (define calls (make-accumulator 0)) 
   (define (reset) (calls (- (calls 0)))) 
   (define (mf a) 
     (cond ((equal? a 'how-many-calls?) (calls 0)) 
           ((equal? a 'reset-count) reset) 
           (else (calls 1) (f a)))) 
   mf) 
  
 (define s (make-monitored sqrt)) 
 (s 100)  ;; 10 
 (s 144)  ;; 12 
 (s 'how-many-calls?) ;; 2 

Small typo: We should use ((equal? a 'reset-count) (reset)).




Shreyashm786

Here's another method , perhaps simpler

  
 (define (make-monitored s) 
    (define count 0) 
    (define (dispatch m) 
       (if (eq? m 'HowMany) count 
          (begin (set! count (+ count 1)) (s m)))) 
 dispatch) 


Cinderella

This solution defines the lexical scope by way of a "helper function". The anonymous function (lambda (x) ...) corresponds to the desired function "mf" and will be returned.

  
 (define (make-monitored f) 
   (define (mf-helper f counter) 
     (lambda (x) 
       (cond ((eq? x 'how-many-calls?) counter) 
             ((eq? x 'reset-count) (begin (set! counter 0) counter)) 
             (else (begin (set! counter (+ counter 1)) (f x)))))) 
   (mf-helper f 0)) 


Rather Iffy

Introduction of a counter by the let form and use of calls instead of references in the dispatch function mf.

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


Denis Manikhin

Daniel-Amariei thank you

  
 (define (make-accumulator acc)  
   (lambda (x)   
     (set! acc (+ acc x))  
     acc))    
    
 (define (make-monitored f)  
   (define calls (make-accumulator 0)) 
   (define (mf a)  
     (cond ((equal? a 'how-many-calls?) (calls 0))  
           ((equal? a 'reset-count) (set! calls (make-accumulator 0)) (calls 0))  
           (else (calls 1) (f a))))  
   mf) 
  


j-minster

Adding another to the pile.

 
  
 (define (make-monitored f) 
   (define counter 0) 
   (define (call inp) 
     (begin 
       (set! counter (inc counter)) 
       (f inp))) 
   (define (mf inp) 
     (cond ((eq? inp 'how-many-calls?) counter) 
           ((eq? inp 'reset-count) (set! counter 0)) 
           (else (call inp)))) 
   mf)