scheme,sicp,solution 3.19,带有无限循环的过程,以防它作为参数提供

时间:2017-07-26 06:09:26

标签: scheme lisp sicp

有人可以帮我解释一下练习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) 
它看起来像魔术。我很感激你的帮助。

1 个答案:

答案 0 :(得分:4)

mystery通过反复剪切每个条目的cdr并将其替换为前一个cdr的{​​{1}}来反转“就地”数组。

如果此列表中有 no 循环,那么当您返回原始x时,它将最终反转。如果一个循环,你将拥有原始数组的指针。

理解这个问题绝对是个棘手的问题。如果你制作一个盒子和指针图表肯定有帮助,你只需绘制3个图表。

自动生成列表图

doing SICP myself的过程中,我发现自己想要一种可视化列表变异的方法(并跳过众多“绘制......”练习的列表图)。我为此写了一个小函数,如果我分享它,我认为你会觉得它很有帮助。

这些图是每次'()(在x函数内)运行时loop运行此函数的示例。

first second third forth last

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

graph-name

上面的代码生成Graphviz图形描述语句,然后必须由(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) (Graphviz)处理以呈现为图形格式。

例如,您可以运行上面的代码并将其传递到dot

dot

此命令会生成一个postscript文件,如果您多次运行$ scheme generate_box_ptr.scm | dot -o ptrs.ps -Tps ,该文件的优点是可以将每个列表分成自己的页面。 list->graphviz还可以输出PNG,PDF和许多其他文件格式manpage describes