简体   繁体   中英

How to add a counter to this scheme function

I would like to add a counter so I can see how many times the iteration runs:

(define tolerance 0.01)
(define (close-enough? x y) (< (abs (- x y)) 0.001))

(define (fixed-point function starting-guess)
  (define iter-count 0)
  (define (evaluate num)
    ; these lines increment the counter using set!
    (set! iter-count (+ iter-count 1))
    (display iter-count) (display " - ") (display num) (display "\n")
    (let ((next-num (function num)))
      (if (close-enough? num next-num)
          next-num
          (evaluate next-num))))
  (evaluate starting-guess))

(fixed-point cos 1.0)

What would be the proper way to do this? Currently I have added in a define and a set! as I couldn't figure out a way to get let to work. Is there a way to do this with let , or what's the suggested way to do this?

Or, I suppose another way is to pass it as a parameter to the iteration function itself:

(define (fixed-point function starting-guess)
  (define (evaluate num iteration-num)
    (display iteration-num) (display " - ") (display num) (display "\n")
    (let ((next-num (function num)))
      (if (close-enough? num next-num)
          next-num
          (evaluate next-num (+ 1 iteration-num)))))
  (evaluate starting-guess 0))

Just like num you just add it aa parameter to your loop function:

(define (fixed-point function starting-guess)
  ;; prints progress
  (define (print-progress iter-count)
    (display iter-count)
    (display " - ") 
    (display num)
    (newline)) 

  ;; main calculating loop 
  (define (evaluate num iter-count)
    (print-progress iter-count)
    (let ((next-num (function num)))
      (if (close-enough? num next-num)
          next-num
          (evaluate next-num (+ iter-count 1)))))

  ;; start process with iter-count 1 since 
  ;; we do increments after display
  (evaluate starting-guess 1))

Notice that your version of this started displaying 0 while your set! version started with 1 . I compensated for this by starting off with 1 instead of 0 .

You could keep the side effects away from fixed-point completely by adding the functionality to the function :

;; pure functional fixed-point
(define (fixed-point function starting-guess)
  (define (evaluate num)
    (let ((next-num (function num)))
      (if (close-enough? num next-num)
          next-num
          (evaluate next-num))))
  (evaluate starting-guess))
    
;; makes a version of function that 
;; reports its first argument and 
;; number of times it's been called
(define (count-and-brag-calls f)
  ;; brag does whatever and
  ;; return the value
  (define (brag v c)
    (display c)
    (display " - ") 
    (display v)
    (newline)
    v) 

  ;; actual implementation
  (let ((count 0))
    (lambda (n)
      (set! count (+ count 1))
      (brag (f n) count))))

;; with verbose output
(fixed-point (count-and-brag-calls cos) 1.0)

;; without side effects gives exact same result without output
(fixed-point cos 1.0)

For the minimal edit, just move the counter's definition (binding) into the top level, and reset the counter each time before you make a call to fixed-point :

(define iter-count 0)  ;; here

(define (fixed-point function starting-guess)
  ;; (define iter-count 0)  ;; commented-out
  ....
  ....
  )

(begin
  (set! iter-count 0)
  (fixed-point ... ... ))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM