我想将原子添加到列表的末尾,我还希望更改原始列表。我写过这个小程序,但它不会改变列表。为什么这样,我怎么能改变它。 PS:我是计划新手。
(define (append! l1 l2)
(set! l1 (append l1 (list l2)) )
)
答案 0 :(得分:1)
您的实现问题是您只更改了函数的参数,但函数退出后函数的“外部”列表保持不变。我们可以使用set-car!
和set-cdr!
就地修改列表,但这有点棘手,因为首先我们必须找到要修改的正确的cons
单元格,然后返回列表的头部:
(define (append! lst atom)
(let ((head lst))
(let loop ((lst lst))
(cond ((null? lst) (list atom))
((null? (cdr lst))
(set-cdr! lst (list atom))
head)
(else (loop (cdr lst)))))))
(define l1 '(1 2 3 4))
l1
=> '(1 2 3 4)
(append! l1 5)
l1
=> '(1 2 3 4 5)
甚至更好,我们可以忘记改变列表并采用函数式编程风格,这是使用Scheme时的推荐方式:
(define l1 '(1 2 3 4))
(define (append-tail lst atom)
(append lst (list atom)))
(define l2 (append-tail l1 5))
l1
=> '(1 2 3 4)
l2
=> '(1 2 3 4 5)
答案 1 :(得分:0)
只需使用句法扩展名:
(define-syntax-rule (append! l1 at)
(set! l1 (append l1 (list at))))
然后
> (define l1 '(1 2 3))
> (append! l1 4)
> l1
'(1 2 3 4)
答案 2 :(得分:0)
set!
会改变绑定但不会改变值,如果它是一对,则set-car!
和set-cdr!
会改变一个值。
set!
用于更改作业。因此,如果您x
和y
都是值"value"
并使用set!
将x
更改为"anothervalue"
。如果您有一个过程并为要重新定义本地名称的其中一个参数分配不同的值,则不更改传递给该过程的变量。
set-car!
和set-cdr
适用于成对。因此,它们会改变值并与变量无关。
例如:
(define x (list 1 2 3)) ; x is (1 2 3)
(define y x) ; y is (1 2 3)
(define z y) ; z is (1 2 3)
;; changing the binding of z
(set! z (append x '(1))) ; z is (1 2 3 1) while x and y still are (1 2 3)
;; changing the value of x
(set-car! x 2) ; both x and y are now (2 2 3)
考虑到这一点,您可以更改变量,但请记住,该变量可以与其他变量共享结构,因此您可以使用set-cdr!
#!r6rs
(import (rnrs)
(rnrs mutable-pairs))
(define (append-elt! lst value)
(when (null? lst)
(assertion-violation 'append! "lst cannot be null" lst))
(let loop ((lst lst))
(if (null? (cdr lst))
(set-cdr! lst (list value))
(loop (cdr lst)))))
(define q (append y y)) ; We make a copy of y with y as shared tail
(append-elt! q 'a) ; we change the last pair of q which also is the last pair of y and z
q ; ==> (1 2 3 1 2 3 a)
x ; ==> (1 2 3 a)
z ; ==> (1 2 3 a)