list 向Scheme中的List添加元素
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3172768/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Adding an element to List in Scheme
提问by name_masked
Below is my code which takes a car element of a list(carVal)
and an list(initialized to empty) as parameters. I want to append the element to the list but the same is not working.
下面是我的代码,它采用列表的汽车元素(carVal)
和列表(初始化为空)作为参数。我想将元素附加到列表中,但同样不起作用。
(define populateValues
(lambda (carVal currVal)
(append currVal(list carVal ))
(display currVal)))
The display shows empty list all the time ()
. Can anyone help me understand why?
显示屏一直显示空列表()
。谁能帮我理解为什么?
回答by Zorf
Well, there is append!
as a primitive, which solves most of your problems, as noted already, Scheme tends to frown on mutation, it is possible, but typically avoided, so all procedures that mutate have a !
(called a bang) at their end.
嗯,有append!
一个原语,它解决了你的大部分问题,正如已经提到的,Scheme 倾向于对突变不屑一顾,这是可能的,但通常会避免,所以所有突变的过程!
在它们的末尾都有一个(称为 bang)。
Also, set!
does not mutate data, it changes an environment, it makes a variable point to another thing, the original data is left unchanged.
此外,set!
不会改变数据,它会改变一个环境,它使一个变量指向另一个事物,原始数据保持不变。
Mutating data in Scheme is quite cumbersome, but, to give you my own implementation of append! to see how it is done:
在 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))))
Note the use of set-cdr!
, which is a true mutator, it only works on pairs, it mutates data in memory, unlike `set!'. If a pair is passed to a function and mutated with set-cdr! or set-car!, it is mutated every-where in the program.
注意 的使用set-cdr!
,它是一个真正的 mutator,它只适用于成对,它改变内存中的数据,与 `set!' 不同。如果将一对传递给函数并使用 set-cdr! 或 set-car!,它在程序中的每个地方都发生了变异。
This obeys the SRFI append! spec which says that it should be variadic and that it should return an undefined value, for instance.
这遵守 SRFI 附加!例如,spec 表示它应该是可变参数并且它应该返回一个未定义的值。
(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
Which displays:
其中显示:
(1 2 3 4 2 3 4 3 1)
(2 3 4 3 1)
(3 1)
As visible, append! can take an infinite number of arguments and it mutates them all but the last.
可见,追加!可以接受无数个参数,并且除了最后一个之外,它都会改变所有参数。
Scheme might not be the ideal language for you though. The use of append! as said before is nonstandard, instead, append is preferred, which does not mutate and is called for its return value. Which I implement as such:
不过,Scheme 可能不是您的理想语言。追加的使用!如前所述是非标准的,相反, append 是首选,它不会发生变异,并为其返回值调用。我是这样实现的:
(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)
Which shows a more familiar Scheme style in the absence of mutation, heavy use of recursion and no use of sequencing.
在没有突变、大量使用递归和不使用排序的情况下,这显示了更熟悉的 Scheme 风格。
Edit: If you just want to add some elements to a list and not per se join two though:
编辑:如果您只想将一些元素添加到列表中而不是本身加入两个:
(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
Which does what you expect
哪个符合您的期望
回答by Eli Barzilay
append
creates a newlist, it does not modify an existing one.- This is because in general, Scheme (and Racket in this case) is a language that prefers functional style.
- You could get somewhat closer with a
set!
-- but even that will disappoint you since it will modify only the local binding. - Note that in Racket in particular, lists are immutable, so there's nothingthat can change a list.
- Furthermore, even if you could modify a list this way, it's a very inefficient way to accumulate long lists, since you have to repeatedly scan the whole list.
- Finally, if you have issues at this level, then I strongly recommend going over HtDP
append
创建一个新列表,它不会修改现有列表。- 这是因为一般来说,Scheme(以及本例中的 Racket)是一种更喜欢函数式风格的语言。
- 你可以更接近
set!
- 但即使这样也会让你失望,因为它只会修改本地绑定。 - 请注意,特别是在 Racket 中,列表是不可变的,因此没有任何东西可以更改列表。
- 此外,即使您可以通过这种方式修改列表,这也是一种非常低效的累积长列表的方法,因为您必须反复扫描整个列表。
- 最后,如果您在此级别遇到问题,那么我强烈建议您使用HtDP
回答by sepp2k
(append foo bar)
returnsthe concatenation of foo
and bar
. It doesn't change either foo
or bar
.
(append foo bar)
返回的串联foo
和bar
。它也不会改变foo
或bar
。
回答by keithm
You have to update the value of currVal with set!. Your example should have
您必须使用 set! 更新 currVal 的值。你的例子应该有
(set! currVal (append currVal (list carVal))
(display currVal)
回答by Dak
You really need to think about what exact functionality you are looking for
您真的需要考虑您正在寻找的确切功能
If you want to mutate a referenced list in place, then you have to do the equivalent of append! (as noted in the other answers). But that is dangerous, BECAUSE you may have other code that is counting on the list being immutable, and if you are going to do that, your procedure needs to have a ! in the end to flag that danger.
如果你想在原地改变一个引用列表,那么你必须做相当于 append! (如其他答案中所述)。但这很危险,因为您可能有其他代码指望列表是不可变的,如果您打算这样做,您的过程需要有一个 ! 最后来标记那个危险。
A cheap approximation to what you want to do, in a more functional style, is:
以更实用的风格,对您想要做的事情的廉价近似是:
(define (populateValues carVal currVal)
(let ((ll (append currVal (list carVal))))
(display ll)
ll))
Note that it makes a new list, does the append, displays the result, and RETURNS the new list as a value. This is a useful debugging technique if you don't have access to the intermediate value: bind to a varible, display or log it, and then return it.
请注意,它创建一个新列表,执行追加,显示结果,并将新列表作为值返回。如果您无法访问中间值,这是一种有用的调试技术:绑定到变量,显示或记录它,然后返回它。