<< Previous exercise (3.1) | Index | Next exercise (3.3) >>
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)
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
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 >>>
(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
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)
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))
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))
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)
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)
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)))))))
Kaihao
This is wrong, because different procedures returned by make-monitored share the same count.
LisScheSic
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.