0

我正在尝试编写一个函数,它接受一个列表(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)

这对我来说似乎很奇怪,因为这两个套装车!和设置-cdr!功能似乎改变了输入列表,而设置!才不是...

任何见解将不胜感激!

4

1 回答 1

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

因此,您可以使用 and 对对进行变异,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))
于 2014-04-01T06:46:30.787 回答