我正在尝试编写一个带有列表(x)和数字(y)的函数,并删除列表中该数字的每个出现。防爆。 (deepdeleting'(0 0 1 2 0 3 0)0)===> '(1 2 3) 这是我到目前为止所做的:
(define (deepdeleting x y)
(if (pair? x)
(if (eqv? (car x) y)
(begin
(set! x (cdr x))
(deepdeleting x y)
)
(deepdeleting (cdr x) y) ; else
)
x ; else
)
)
代码有效,但我的问题是我希望它修改原始列表,而不仅仅是返回一个新列表。现在发生了这样的事情:
> (define list '(0 0 1 2 0 3 0))
> (deepdeleting list 0)
(1 2 3)
> list
(0 0 1 2 0 3 0) ; <<< I want this to be (1 2 3)
这对我来说既然是这套车也很奇怪!和set-cdr!函数似乎改变了输入列表,而设置!没有......
非常感谢任何见解!
答案 0 :(得分:2)
当您使用set!
时,您正在重新定义最内层绑定:
(define test 10)
(set! test 11) ; changes global test to 11
(define (change-test value)
(set! test value))
(change-test 12) ; changes global test to 12
(define (change-test! value new-value)
(display value)
(set! value new-value) ; changes the local binding value
(display value))
(change-test! test 13) ; changes nothing outside of change-test, prints 12 then 13
变量绑定与列表结构突变完全不同。在这里,绑定用于指向被更改的对:
(define lst '(1 2 3))
(define lst2 (cdr lst)) ; lst2 shares structure with lst
(set-cdr! lst2 '(8 7 6 5))
lst2 ; ==> (2 8 7 6 5)
lst ; ==> (1 2 8 7 6 5) the original binding share structure thus is changed too
(set-cdr! lst lst) ; makes a circular never ending list (1 1 1 1 ...)
(eq? lst (cdr lst)) ;==> #t
(set-car! lst 2) ; changes lst to be never ending list (2 2 2 2 ...)
因此,您可以使用set-cdr!
和set-car!
变异对,并且对原始列表的绑定将指向第一对。因此,您需要以与第一对相同的对开始结果。有了这个,你就可以这样做变异过程:
#!r6rs
(import (rnrs) (rnrs mutable-pairs))
(define (remove! lst e)
(if (pair? lst)
(let loop ((prev lst)(cur (cdr lst)))
(if (pair? cur)
(if (eqv? (car cur) e)
(begin
(set-cdr! prev (cdr cur))
(loop prev (cdr cur)))
(loop cur (cdr cur)))
(if (eqv? (car lst) e)
(if (pair? (cdr lst))
(begin
(set-car! lst (cadr lst))
(set-cdr! lst (cddr lst)))
(error 'first-pair-error "Not possible to remove the first pair"))
#f)))
#f))
(define test '(0 0 1 2 0 3 0))
(define test2 (cdr test))
test2 ;==> (0 1 2 0 3 0)
(remove! test 0)
test ; ==> (1 2 3)
test2 ; ==> (0 1 2 0 3 0)
(remove! '(0) 0)
; ==> first-pair-error: Not possible to remove the first pair
(remove! '(1 2 3) 2) ; this works too but you have no way of checking
虽然lst
在删除期间绑定到列表,但同一列表中有一个元素少,但在删除之外没有绑定到它!程序,结果永远丢失。
修改强>
对于R5RS,请删除前两行并添加error
:
;; won't halt the program but displays the error message
(define (error sym str)
(display str)
(newline))