以下是我的代码,它以一个列表元素(carVal)
和一个参数初始化为空的列表作为参数。我想将该元素附加到列表中,但不起作用。
(define populateValues
(lambda (carVal currVal)
(append currVal(list carVal ))
(display currVal)))
显示器一直显示空列表
()
。有人能帮我理解为什么吗?对于大多数问题,原语append!
可以解决。正如前面所提到的,Scheme 不赞成变异,虽然这是可能的,但通常要避免使用。因此,所有会导致变异的过程都在结尾加上一个!
(称为bang)。
set!
并不会改变数据,它只更改了环境,使变量指向另一个东西,原始数据保持不变。
在 Scheme 中突变数据相当麻烦,但是,我会给你展示我自己实现的append!
,让你看看它是如何完成的:
(define (append! lst . lsts)
(if (not (null? lsts))
(if (null? (cdr lst))
(begin
(set-cdr! lst (car lsts))
(apply append! (car lsts) (cdr lsts)))
(apply append! (cdr lst) lsts))))
set-cdr!
,它是一个真正的变异器,只能作用于对,它会在内存中改变数据,不像 `set!'。如果一个对被传递到一个函数中,并用 set-cdr! 或 set-car! 进行突变,则它在程序中的任何地方都被突变了。(define l1 (list 1 2 3 4))
(define l2 (list 2 3 4))
(define l3 (list 3 1))
(append! l1 l2 l3)
l1
l2
l3
显示:
(1 2 3 4 2 3 4 3 1)
(2 3 4 3 1)
(3 1)
(define (append . lsts)
(cond
((null? lsts) '())
((null? (car lsts)) (apply append (cdr lsts)))
(else (cons (caar lsts) (apply append (cdar lsts) (cdr lsts))))))
> (append (list 1 2 3) (list 4 5 6) (list 'reasonable 'behavior))
(1 2 3 4 5 6 reasonable behavior)
在没有变异、大量使用递归和不使用排序的情况下,显示更熟悉的Scheme风格。
编辑:如果你只想向列表中添加一些元素,而不是连接两个列表:
(define (extend l . xs)
(if (null? l)
xs
(cons (car l) (apply extend (cdr l) xs))))
(define (extend! l . xs)
(if (null? (cdr l))
(set-cdr! l xs)
(apply extend! (cdr l) xs)))
(extend '(0 1 2 3) 4 5 6)
(define list1 '(0 1 2 3))
(extend! list1 4 5 6)
list1
它做你所期望的事情
append
创建一个新的列表,它不会修改现有的列表。set!
使它更接近,但即使如此,它也只会修改局部绑定。box
,它是指向(可变)值的指针。但是我怀疑你是否真的需要这个功能 - 新手经常认为必须拥有这个功能,因为他们习惯于只能通过改变值来实现操作。 - Eli Barzilay(append foo bar)
返回 连接 foo
和 bar
的结果。它不会改变 foo
或者 bar
。
你需要使用set!更新currVal的值。你的例子应该有
(set! currVal (append currVal (list carVal))
(display currVal)
你真的需要考虑清楚你所寻找的确切功能是什么。
如果你想要在原地改变一个引用列表,那么你必须做相当于append!的操作(如其他答案中所述)。但这是危险的,因为你可能有其他代码依赖于该列表是不可变的,如果你要这样做,你的过程需要在结尾加上一个!来标记这种危险。
在更函数式的风格中,你想要做的廉价近似是:
(define (populateValues carVal currVal)
(let ((ll (append currVal (list carVal))))
(display ll)
ll))