Scheme 方案,sicp,解决方案3.19,无限循环过程在作为参数提供的情况下有效

Scheme 方案,sicp,解决方案3.19,无限循环过程在作为参数提供的情况下有效,scheme,lisp,sicp,Scheme,Lisp,Sicp,有人能帮我澄清练习3.19的一个可能的解决方案吗。以实例列表循环为参数,给出了过程奥秘是无限循环。然而,当我们使用程序eq?若要检查列表是否包含循环,它将工作并提供真实值 (define (last-pair x) (if (null? (cdr x)) x (last-pair (cdr x)) ) ) (define (ma

有人能帮我澄清练习3.19的一个可能的解决方案吗。以实例列表循环为参数,给出了过程奥秘是无限循环。然而,当我们使用程序eq?若要检查列表是否包含循环,它将工作并提供真实值

(define (last-pair x)     
        (if (null? (cdr x))          
            x           
            (last-pair (cdr x))      
        ) 
)            
(define (make-cycle x)                
        (set-cdr! (last-pair x) x)                         
)                    
(define (mystery x)               
        (define (loop x y)                    
                (if (null? x)                
                    y                
                    (let ((temp (cdr x)))             
                          (set-cdr! x y)                     
                          (loop temp x)                  
                    )                
                )                   
        )                 
        (loop x '())              
)             
(define t (list 1 2 3))            
(define w (make-cycle t))                 
(eq? (mystery t) t) 

看起来很神奇。如果有任何帮助,我将不胜感激。

神秘
通过反复剪掉每个条目的
cdr
并将其替换为上一个
x
cdr
来反转“就地”数组

如果此列表没有循环,那么当您返回到原始的
'()
时,它将结束反转。如果有一个循环,您将拥有原始数组的指针

这绝对是一个难以理解的问题。如果你做一个方框和指针图,它肯定会有帮助,你只需要画3个图表


自动生成列表图表 在这个过程中,我发现自己想要一种可视化列表突变的方法(并跳过无数的“绘制列表图…”练习)。我为此编写了一个小函数,我想如果我共享它,您可能会发现它很有用

这些图表是每次运行
循环
(在
神秘
函数中)时在
x
上运行此函数的示例

下面的代码是我用来生成这些图的代码。我作为Scheme新手编写了这段代码,但它的使用非常简单:函数(
list->graphviz
)接受一个参数
lst
,它是您想要作为图表的列表,以及一个可选参数
graph name
,它为图形提供了一个特殊的名称

(define* (list->graphviz lst #:optional graph-name)
  """Convert a list into a set of Graphviz instructions
       `lst' is the list you'd like a diagram of
       `graph-name` is an optional parameter indicating the name you'd like to give the graph."""

  (define number 0)
  (define result "")
  (define ordinals '())
  (define (result-append! str)
    (set! result (string-append result str)))

  (define* (nodename n #:optional cell)
    (format #f "cons~a~a" n (if cell (string-append ":" cell) "")))

  (define* (build-connector from to #:optional from-cell)
    (format #f "\t~a -> ~a;~%" (nodename from from-cell) (nodename to)))

  (define (build-shape elt)
    (define (build-label cell)
      (cond ((null? cell) "/");; "∅") ; null character
            ((pair? cell) "*");; "•") ; bullet dot character
            (else (format #f "~a" cell))))
    (set! number (+ number 1))

    (format #f "\t~a [shape=record,label=\"<car> ~a | <cdr> ~a\"];~%"
            (nodename number)
            (build-label (car elt))
            (build-label (cdr elt))))

  (define* (search xs #:optional from-id from-cell)
    (let ((existing (assq xs ordinals)))
      (cond
       ;; if we're not dealing with a pair, don't bother making a shape
       ((not (pair? xs)) (result-append! "\tnothing [shape=polygon, label=\"not a pair\"]\n"))
       ((pair? existing)
        (result-append! (build-connector from-id (cdr existing) from-cell)))
       (else
        (begin
          (result-append! (build-shape xs))
          (set! ordinals (assq-set! ordinals xs number))
          (let ((parent-id number))
            ;; make a X->Y connector
            (if (number? from-id)
                (result-append! (build-connector from-id parent-id from-cell)))
            ;; recurse
            (if (pair? (car xs)) (search (car xs) parent-id "car"))
            (if (pair? (cdr xs)) (search (cdr xs) parent-id "cdr"))))))))

  (search lst)
  (string-append "digraph " graph-name " {\n" result "}\n"))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;; Here is where `mystery' begins ;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define t '(1 2 3))
(set-cdr! (cddr t) t)

(define (mystery x)
  (define (loop x y graph-num)
    (display (list->graphviz x (format #f "graph~a" graph-num)))
    (if (null? x)
        y
        (let ((temp (cdr x)))
          (set-cdr! x y)
          (loop temp x (+ 1 graph-num)))))
  (loop x '() 0))

(mystery t)

如果您多次运行
list->graphviz
,此命令将生成一个postscript文件,该文件的优点是可以将每个列表分隔为自己的页面
dot
还可以输出PNG、PDF和许多其他文件格式,如。

secrety
通过反复剪掉每个条目的
cdr
并将其替换为上一个
x
cdr
来反转“在位”数组

如果此列表没有循环,那么当您返回到原始的
'()
时,它将结束反转。如果有一个循环,您将拥有原始数组的指针

这绝对是一个难以理解的问题。如果你做一个方框和指针图,它肯定会有帮助,你只需要画3个图表


自动生成列表图表 在这个过程中,我发现自己想要一种可视化列表突变的方法(并跳过无数的“绘制列表图…”练习)。我为此编写了一个小函数,我想如果我共享它,您可能会发现它很有用

这些图表是每次运行
循环
(在
神秘
函数中)时在
x
上运行此函数的示例

下面的代码是我用来生成这些图的代码。我作为Scheme新手编写了这段代码,但它的使用非常简单:函数(
list->graphviz
)接受一个参数
lst
,它是您想要作为图表的列表,以及一个可选参数
graph name
,它为图形提供了一个特殊的名称

(define* (list->graphviz lst #:optional graph-name)
  """Convert a list into a set of Graphviz instructions
       `lst' is the list you'd like a diagram of
       `graph-name` is an optional parameter indicating the name you'd like to give the graph."""

  (define number 0)
  (define result "")
  (define ordinals '())
  (define (result-append! str)
    (set! result (string-append result str)))

  (define* (nodename n #:optional cell)
    (format #f "cons~a~a" n (if cell (string-append ":" cell) "")))

  (define* (build-connector from to #:optional from-cell)
    (format #f "\t~a -> ~a;~%" (nodename from from-cell) (nodename to)))

  (define (build-shape elt)
    (define (build-label cell)
      (cond ((null? cell) "/");; "&#x2205;") ; null character
            ((pair? cell) "*");; "&#x2022;") ; bullet dot character
            (else (format #f "~a" cell))))
    (set! number (+ number 1))

    (format #f "\t~a [shape=record,label=\"<car> ~a | <cdr> ~a\"];~%"
            (nodename number)
            (build-label (car elt))
            (build-label (cdr elt))))

  (define* (search xs #:optional from-id from-cell)
    (let ((existing (assq xs ordinals)))
      (cond
       ;; if we're not dealing with a pair, don't bother making a shape
       ((not (pair? xs)) (result-append! "\tnothing [shape=polygon, label=\"not a pair\"]\n"))
       ((pair? existing)
        (result-append! (build-connector from-id (cdr existing) from-cell)))
       (else
        (begin
          (result-append! (build-shape xs))
          (set! ordinals (assq-set! ordinals xs number))
          (let ((parent-id number))
            ;; make a X->Y connector
            (if (number? from-id)
                (result-append! (build-connector from-id parent-id from-cell)))
            ;; recurse
            (if (pair? (car xs)) (search (car xs) parent-id "car"))
            (if (pair? (cdr xs)) (search (cdr xs) parent-id "cdr"))))))))

  (search lst)
  (string-append "digraph " graph-name " {\n" result "}\n"))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;; Here is where `mystery' begins ;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define t '(1 2 3))
(set-cdr! (cddr t) t)

(define (mystery x)
  (define (loop x y graph-num)
    (display (list->graphviz x (format #f "graph~a" graph-num)))
    (if (null? x)
        y
        (let ((temp (cdr x)))
          (set-cdr! x y)
          (loop temp x (+ 1 graph-num)))))
  (loop x '() 0))

(mystery t)

如果您多次运行
list->graphviz
,此命令将生成一个postscript文件,该文件的优点是可以将每个列表分隔为自己的页面
dot
还可以输出PNG、PDF和许多其他文件格式作为。如何绘制每个列表的cons单元格的内容?
eq?
做什么?调用
(生成循环t)
后,t是否循环?据我所知,t在执行行(生成循环t)后变为循环。(eq?(t)t)是检测列表内循环的测试。如果有循环则为真,否则为假。如果我尝试执行,行“(eq?(神秘的w)w)”抛出错误。我不明白为什么。
eq?
在其参数相同时返回true(想想“指针比较”):。特别是,没有尝试检测循环。除非另有规定,否则接受列表的函数可能不会在有循环时终止。如何绘制每个列表的cons单元格的内容?
eq?
做什么?调用
(生成循环t)
后,t是否循环?据我所知,t在执行行(生成循环t)后变为循环。(eq?(t)t)是检测列表内循环的测试。如果有循环则为真,否则为假。如果我尝试执行,行“(eq?(神秘的w)w)”抛出错误。我不明白为什么。
eq?
在其参数相同时返回true(想想“指针比较”):。特别是,没有尝试检测循环。除非另有规定,否则接受列表的函数可能不会在出现循环时终止。非常感谢您的回复。但我仍然不明白为什么在循环的情况下,我会得到原始数组的指针,为什么我会得到一些东西,因为过程(神秘z)根本不会终止。请你澄清一下,3个图应该说明什么。我会很感激的。非常感谢。我画了所有的细节后才明白。很抱歉再次打扰您。@Oliver我添加了关于如何自动绘制列表的更多信息。非常感谢您的回复。但我仍然不明白为什么在循环的情况下,我会得到原始数组的指针,为什么我会得到一些东西,因为过程(神秘z)根本不会终止。请你澄清一下,3个图应该说明什么。我会很感激的。非常感谢。我画了所有的细节后才明白。抱歉再次打扰您。@Oliver我添加了一些关于如何自动