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 :(得分: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!
相同,没有突变。