2017-05-08 25 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保證......只是說'。 –