如何通过这个评估?

How to step through this evaluation?

我想看看平方根的值是如何迭代改进的。例如以下内容:

#lang sicp
(define (square x) (* x x))
(define (average x y) (/ (+ x y) 2))
(define (improve guess x) (average guess (/ x guess)))
(define (good-enough? guess x) (< (abs (- (square guess) x)) 0.001 ))
(define (sqrt-iter guess x) (if (good-enough? guess x) guess (sqrt-iter (improve guess x) x)))
(define (sqrt x) (sqrt-iter 1.0 x))
(sqrt 2)

它得到如下值:

1 1
2 1.5
3 1.4166666666666665
4 1.4142156862745097

作为我想要展示的示例,在 Javascript 我会做类似的事情:

const sqrt_iter = (guess, x) => {
    console.log(count++, guess);
    return good_enough(guess, x) ? guess : sqrt_iter(improve(guess, x), x);
}
const sqrt = x => sqrt_iter(1.0, x);

如何在 DrRacket/SICP 中打印或跟踪这些中间值?我试过 (trace sqrt) 但它说找不到。

我相信 Racket 有一些奇特的跟踪功能。但是有一句名言(我想是约翰·福德拉罗说的):

Lisp [for which read Racket] is the programmable programming language.

意思是:如果没有追踪工具,或者懒得做,你就写一个。

这是我用五分钟写的一个基本的:

#lang racket

(provide define/traced)

(define trace-depths (make-parameter 0))

(define (spaces n)
  (make-string n #\ ))

(define-syntax define/traced
  (syntax-rules ()
    [(_ (name arg ...) form ...)
     (define/traced name (λ (arg ...) form ...))]
    [(_ (name . args) form ...)
     (define/traced name (λ args form ...))]
    [(_ name function)
     (define name
       (λ args
         (let* ([depth (trace-depths)]
                [prefix (spaces depth)])
           (parameterize ([trace-depths (+ depth 1)])
             (printf "~A~S ...~%" prefix `(,'name ,@args))
             (call-with-values
              (thunk (apply function args))
              (λ results
                (printf "~A-> ~S~%" prefix results)
               (apply values results)))))))]))

将其保存在名为 define-traced.rkt 的文件中,然后 require 并告诉它跟踪您关心的程序:

#lang racket

(require "define-traced.rkt")

(define (square x) (* x x))
(define (average x y) (/ (+ x y) 2))
(define/traced (improve guess x) (average guess (/ x guess)))
(define (good-enough? guess x) (< (abs (- (square guess) x)) 0.001 ))
(define/traced (sqrt-iter guess x) (if (good-enough? guess x) guess (sqrt-iter (improve guess x) x)))
(define (sqrt x) (sqrt-iter 1.0 x))
(sqrt 2)

这将正式打印:

(sqrt-iter 1.0 2) ...
 (improve 1.0 2) ...
 -> (1.5)
 (sqrt-iter 1.5 2) ...
  (improve 1.5 2) ...
  -> (1.4166666666666665)
  (sqrt-iter 1.4166666666666665 2) ...
   (improve 1.4166666666666665 2) ...
   -> (1.4142156862745097)
   (sqrt-iter 1.4142156862745097 2) ...
   -> (1.4142156862745097)
  -> (1.4142156862745097)
 -> (1.4142156862745097)
-> (1.4142156862745097)
1.4142156862745097

请注意,当我说这是一个 初级 设施时,我是认真的:特别是它可能会将尾调用变成 non-tail 调用,还有许多其他它有问题。但是编写手册所花的时间比阅读一些毛茸茸的设施的手册所花的时间要少。如果我只打算使用这个东西一次(这可能是我唯一一次使用它:它只是把它变成一个文件,所以我可以在另一个文件中需要它)这是值得的。这是 Lisp-family 语言的荣耀之一。

尝试begin with printf(同时添加一个变量作为计数器):

#lang racket

(define (square x)
  (* x x))

(define (average x y)
  (/ (+ x y) 2))

(define (improve guess x)
  (average guess (/ x guess)))

(define (good-enough? guess x)
  (< (abs (- (square guess) x)) 0.001 ))

(define (sqrt-iter guess x count)
  (begin
    (printf "~a ~a \n" count guess)
    (if (good-enough? guess x)
        guess
        (sqrt-iter (improve guess x)
                   x
                   (+ 1 count)))))

(define (sqrt x) (sqrt-iter 1.0 x 1))
(sqrt 2)
1 1.0 
2 1.5 
3 1.4166666666666665 
4 1.4142156862745097

1.4142156862745097

注意我用的是#lang racket-好像sicp没有print或者printf,不过你可以试试write or display来实现相似的结果。

@ignis 为此提供了适当的技术。然而,在你潜入 define-syntax 的深海之前,也许你想要 quick-and-dirty 方法 -

#lang sicp

(define (sqrt-iter guess x)
  (for-each display (list "sqrt-iter" " " guess " " x "\n"))
  (if (good-enough? guess x)
      guess
      (sqrt-iter (improve guess x) x)))

(sqrt 2)
sqrt-iter 1.0 2
sqrt-iter 1.5 2
sqrt-iter 1.4166666666666665 2
sqrt-iter 1.4142156862745097 2
1.4142156862745097