下面是我的代码,它将列表(carVal)
的car元素和列表(初始化为空)作为参数。我想将元素附加到列表中,但同样不起作用。
(define populateValues
(lambda (carVal currVal)
(append currVal(list carVal ))
(display currVal)))
显示屏始终显示空列表()
。谁能帮我理解为什么?
答案 0 :(得分:25)
好吧,有append!
作为原语,它可以解决你的大部分问题,正如已经指出的那样,Scheme倾向于对变异不屑一顾,有可能,但通常会避免,所以变异的所有程序都有{ {1}}(称为爆炸声)在他们的最后。
此外,!
不会改变数据,它会改变环境,它会使变量指向另一个东西,原始数据保持不变。
在Scheme中变异数据非常麻烦,但是,为了给你我自己的追加实现!看看它是如何完成的:
set!
注意使用(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))))
,它是一个真正的mutator,它只适用于对,它会改变内存中的数据,这与`set!'不同。如果一对传递给一个函数并用set-cdr进行变异!或者set-car !,它会在程序中的每个地方发生变异。
这服从SRFI追加!例如,它应该是可变参数并且它应该返回一个未定义的值。
set-cdr!
显示:
(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
可见,追加!可以采用无数个参数,并且除了最后一个之外它都会改变它们。
Scheme可能不是你理想的语言。使用追加!如前所述是非标准的,相反,append是首选的,它不会发生变异并被称为其返回值。我实施的是这样的:
(1 2 3 4 2 3 4 3 1)
(2 3 4 3 1)
(3 1)
在没有突变,大量使用递归的情况下,显示了更熟悉的Scheme风格 并没有使用测序。
编辑:如果您只是想将一些元素添加到列表中而不是本身加入两个:
(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 'granny 'porn))
(1 2 3 4 5 6 granny porn)
您的期望是什么
答案 1 :(得分:5)
append
创建新列表,但不会修改现有列表。set!
稍微接近 - 但即使这样也会让你失望,因为它只会修改本地绑定。答案 2 :(得分:2)
(append foo bar)
返回 foo
和bar
的串联。它不会更改foo
或bar
。
答案 3 :(得分:0)
您必须使用set!更新currVal的值。你的例子应该有
(set! currVal (append currVal (list carVal))
(display currVal)
答案 4 :(得分:0)
您真的需要考虑您正在寻找的确切功能
如果你想改变一个引用的列表,那么你必须做相当于追加! (如其他答案中所述)。但这很危险,因为你可能有其他代码指望列表是不可变的,如果你要这样做,你的程序需要有一个!最后标志着这种危险。
以更实用的方式,您想要做的便宜的近似是:
(define (populateValues carVal currVal)
(let ((ll (append currVal (list carVal))))
(display ll)
ll))
请注意,它会生成一个新列表,附加,显示结果,并将新列表作为值返回。如果您无权访问中间值,这是一种有用的调试技术:绑定到变量,显示或记录它,然后返回它。