Scheme中一个程序的while循环工作机制

While loops working mechanism of a program in Scheme

DrRacket 用户。

我很难理解这个程序 works.I 是如何自己编写的,它做了它必须做的事情,但我不明白是如何做到的。

我将 while 循环定义为:

(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!))

我们缺少第一个元素,但这个程序以某种方式将其保留并给出了所需的输出。我想知道它是如何工作的以及是否有另一种遍历给定列表的方法。

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

在您的 mlist-map-while 中,变量 x 改变了 car,然后将 x 代表的 改变为cdrx。它 从不 改变 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)

请注意,这里我们递归并更改 lst 是什么,成为 cdr。每个递归都有自己的 lst,不要与调用者自己的相混淆。它最终与您示例中的 set! 相同,没有突变。