2017-05-08 50 views
1

中的程序的循环工作机制。DrRacket用户的程序

我很努力地理解这个程序是如何工作的。我自己写了它,它做了它必须做的事但我不明白怎么做。

我定义循环为:

(define (while test body) 
    (if (test) 
     (begin 
     (body) 
     (while test body)) 
     (void))) 

现在我需要编写一个给定的程序适用于一个可变列表中的每个元素的程序。

这里是我写的:

(define (mlist-map-while f x) 
    (while (lambda() (not (null? x))) 
    (lambda() 
     (set-mcar! x (f (mcar x))) 
     (set! x (mcdr x)))) 
    (void)) 

所以,定义

list1 (mlist 1 2 3) 

和应用

(mlist-map-while (lambda (x) (+ x 1)) list1) 

我们得到'(2 3 4)

,我不明白的事情是列表的第一个元素是如何保持它,因为如果它这样做我怎么写到这里

(set! x (mcdr x)) 

,设置-mcar!必须是无用的,是第一道工序与第二个重叠。就像这个例子:

(define list1 (mlist 1 2 3)) 
(set-mcar! list1 9) 
(set-mcdr! list1 (mcdr list!)) 

,我们缺乏的第一要素,但这个方案在某种程度上离开它,并给出所需的输出。我想知道它是如何工作的以及是否有另一种遍历给定列表的方式。

回答

0

set-cdr! abd set!有很大区别。第一个改变了这个对的cdr指针,而后者改变了绑定,因此这个名字应该指向什么。

在你mlist-map-while变量x改变car,然后改变什么x代表,是xcdr。它从未改变cdr让你结合list1总是指向第一对同时x指向第一个,然后第二,等...

因此它更像是这样的:

(define list1 (mlist 1 2 3)) 
(define list1-ref list1)  ; variable pointing to the same value as list1 
(set-mcar! list1-ref 9)  ; set-car! changes the pair 
(set! list1-ref (mcdr list)) ; set! updates what list1-ref points to 
list1 ; ==> (9 2 3) 
list-ref ; ==> (2 3) 

你可以遍历以同样的方式列表,而无需使用set!,用递归:

(define (fold function init lst) 
    (if (null? lst) 
     init 
     (fold function 
      (function (car lst) init) 
      (cdr lst)))) 

(fold + 0 '(1 2 3) 
; ==> 6 

(fold cons '() '(1 2 3)) 
; ==> (3 2 1) 

请注意,在这里我们递归和改变什么lstcdr。每个递归都有它自己的lst,这是不应该与来电者自己混淆。在你的例子中,它的结果与set!一样,没有突变。

+0

那么这是否意味着如果我在你的例子中定义了list1-ref((set!list1-ref(mcdr list)))值2和3仍然指向list1的第二个和第三个值?如果我改变它们,list1的值将分别改变? – Dmitrii

+0

是的。由于列表是如何建模的,每个元素对都有一个元素和一个链接到列表的其余部分。 '(mlist 1 2 3)'与'(mcons 1(mcons 2(mcons 3'()))' – Sylwester

+0

'相同'Scheme虽然具有TCO保证......只是说'。 –