同时在Scheme中循环一个程序的工作机制

时间:2017-05-08 19:39:34

标签: while-loop scheme racket scoping mutability

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

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

1 个答案:

答案 0 :(得分:0)

set-cdr! abd set!之间存在很大差异。第一个改变了对的cdr指针,而后者改变了绑定,因此名称应该指向。

mlist-map-while变量x改变car,然后更改x 代表的内容,成为cdr x从不更改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!相同,没有突变。