如何使用方案宏来显示评估树

时间:2013-02-11 03:42:57

标签: scheme graphviz sicp

我修改了SICP中count-change函数的代码,以便在函数递归时显示一对。该对的格式为"(cc a k)" -> "(cc a (- k 1))""(cc a k)" -> "(cc (- a (d k)) k)",我的目标是使用GraphViz构建一个DOT文件以显示树递归。

这是一个示例图片,由以下代码生成: enter image description here

这是方案代码:

    ; Count Change

    (define (count-change amount)
      (cc amount 5))

    (define (cc amount kinds-of-coins)
      (begin
        (cond ((= amount 0) 1)
          ((or (< amount 0) (= kinds-of-coins 0)) 0)
          (else (+ 
             (begin 
               (display "\"")
               (display `(cc ,amount ,kinds-of-coins))
               (display "\"")
               (display " -> ")
               (display "\"")
               (display `(cc ,amount ,(- kinds-of-coins 1)))
               (display "\"")
               (display "\n")
               (cc amount (- kinds-of-coins 1))
               )
             (begin 
               (display "\"")
               (display `(cc ,amount ,kinds-of-coins))
               (display "\"")
               (display " -> ")
               (display "\"")
               (display `(cc ,(- amount (first-denomination kinds-of-coins)) ,kinds-of-coins))
               (display "\"")
               (display "\n")
               (cc (- amount (first-denomination kinds-of-coins)) kinds-of-coins)
               )
             )
            ))))

                        ; first-denomination takes the number of kinds of coins and returns the denomination of the first kind
      (define (first-denomination kinds-of-coins)
        (cond ((= kinds-of-coins 1) 1)
          ((= kinds-of-coins 2) 5)
          ((= kinds-of-coins 3) 10)
          ((= kinds-of-coins 4) 25)
          ((= kinds-of-coins 5) 50)))

    (count-change 11)

原始代码为here

我已经阅读过有关方案宏的内容,我认为他们可以通过允许我在带有显示的begin语句中“封装”对(cc。)的调用来解决这个问题,以输出正在发生的事情。递归时间。

如何使用Scheme宏完成此操作?

注意:我知道我的图像不准确,我需要找到一种使节点不同的方法,这样图形就是树,而不仅仅是DAG。但是,这超出了这个问题的范围。

2 个答案:

答案 0 :(得分:4)

宏不是你想要的。这个工作更合适的工具是一个简单的本地函数,它知道cc的旧参数和新参数,并处理打印graphviz文本并进行递归调用:

(define (cc amount kinds-of-coins)
  (let ((recur (lambda (new-amount new-kinds)
                 (begin
                   (display "\"")
                   (display `(cc ,amount ,kinds-of-coins))
                   (display "\"")
                   (display " -> ")
                   (display "\"")
                   (display `(cc ,new-amount ,new-kinds))
                   (display "\"")
                   (display "\n")
                   (cc new-amount new-kinds)))))
    (cond ((= amount 0) 1)
          ((or (< amount 0) (= kinds-of-coins 0)) 0)
          (else (+ 
                 (recur amount (- kinds-of-coins 1))
                 (recur (- amount (first-denomination kinds-of-coins)) kinds-of-coins))))))

您没有说明您正在使用哪种Scheme实现,但是对于某些实现,还可以执行一些小的语法清理,以使此代码看起来更好。

答案 1 :(得分:2)

这是一种抽象jacobm建议的模式的方法:

;; Add graphviz tracing to a definition:
(define-syntax define/graphviz-trace
  (syntax-rules ()
    [(_ (id args ...) body ...)
     (define (id args ...)
       (let* ([real-id id]
              [old-args (list args ...)]
              [id (lambda (args ...)
                    (define new-args (list args ...))
                    (print-trace 'id old-args new-args)
                    (real-id args ...))])
         body ...))]))

;; print-trace: symbol list list -> void
(define (print-trace id old-args new-args)
  (display "\"")
  (display `(id ,@old-args))
  (display "\"")
  (display " -> ")
  (display "\"")
  (display `(id ,@new-args))
  (display "\"")
  (display "\n"))

; first-denomination takes the number of kinds of coins and
; returns the denomination of the first kind
(define (first-denomination kinds-of-coins)
  (cond ((= kinds-of-coins 1) 1)
        ((= kinds-of-coins 2) 5)
        ((= kinds-of-coins 3) 10)
        ((= kinds-of-coins 4) 25)
        ((= kinds-of-coins 5) 50)))

;; Example:
(define/graphviz-trace (cc amount kinds-of-coins)
  (cond ((= amount 0) 1)
        ((or (< amount 0) (= kinds-of-coins 0)) 0)
        (else (+ (cc amount (- kinds-of-coins 1))
                 (cc (- amount (first-denomination kinds-of-coins))
                     kinds-of-coins)))))