为什么没有这个集合!函数修改Scheme(r5rs)中的原始列表?

时间:2014-04-01 05:47:05

标签: functional-programming scheme r5rs

我正在尝试编写一个带有列表(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!函数似乎改变了输入列表,而设置!没有......

非常感谢任何见解!

1 个答案:

答案 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))