SICP Exercise 3.2
Question
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
Answer
We are using let to keep track of our counter. Obviously, we need to start at
0 since this is how often the function has been run initially. From this point
on, every single run that does not use one of our reserved keywords as a
parameter will increment the counter by 1.
(define (make-monitored f)
(let ((counter 0))
(define (mf x)
(cond ((eq? x 'how-many-calls?)
counter)
((eq? x 'reset-count)
(set! counter 0))
(else (begin (set! counter (+ counter 1))
(f x)))))
mf))
Let’s test it:
(s 100)
(s 25)
(s 'how-many-calls?)
(s 'reset-count)
(s 'how-many-calls?)
The results are what we would expect:
10
5
2
0