如何为这个方案函数添加一个计数器

How to add a counter to this scheme function

我想添加一个计数器,这样我就可以看到迭代运行了多少次:

(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)

执行此操作的正确方法是什么?目前我已经添加了 defineset!,因为我想不出让 let 工作的方法。有没有办法用 let 来做到这一点,或者建议的方法是什么?

或者,我想另一种方法是将它作为参数传递给迭代函数本身:

(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))

就像num一样,您只需将其添加到循环函数中即可:

(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))

请注意,您的版本开始显示 0,而您的 set! 版本以 1 开头。我通过从 1 而不是 0.

开始来弥补这一点

您可以通过将功能添加到 function:

来完全避免副作用 fixed-point
;; 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)

对于最小的编辑,只需将计数器的定义(绑定)移动到顶层,并在每次之前重置计数器 打电话给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 ... ... ))