在Scheme中的List中添加一个元素

发布于 2024-09-07 22:55:57 字数 273 浏览 5 评论 0原文

下面是我的代码,它采用列表(carVal) 的 car 元素和列表(初始化为空)作为参数。我想将元素追加到列表中,但同样不起作用。

(define populateValues
   (lambda (carVal currVal)
      (append currVal(list carVal ))
       (display currVal)))

显示屏始终显示空列表 () 。谁能帮我理解为什么?

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.

(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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

寂寞笑我太脆弱 2024-09-14 22:55:57

好吧,有 append! 作为一个原语,它解决了你的大部分问题,正如已经指出的,Scheme 倾向于不赞成突变,这是可能的,但通常会避免,所以所有突变的过程都有一个! (称为“爆炸”)在其末尾。

另外,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!,它在程序中的每个地方都发生了变化。

这遵循 SRFI 附录!例如,规范规定它应该是可变的,并且应该返回一个未定义的值。

(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)

如可见,追加!可以接受无限多个参数,并且它会改变除最后一个之外的所有参数。

不过,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 'reasonable 'behavior))
(1 2 3 4 5 6 reasonable behavior)

在没有突变、大量使用递归的情况下,它显示了更熟悉的方案风格
并且不使用测序。

编辑:如果您只想将一些元素添加到列表中,而不是本身加入两个元素:

(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

这符合您的期望

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.

Also, set! does not mutate data, it changes an environment, it makes a variable point to another thing, the original data is left unchanged.

Mutating data in Scheme is quite cumbersome, but, to give you my own implementation of append! to see how it is done:

(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.

This obeys the SRFI append! spec which says that it should be variadic and that it should return an undefined value, for instance.

(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:

(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)

Which shows a more familiar Scheme style in the absence of mutation, heavy use of recursion
and no use of sequencing.

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

征﹌骨岁月お 2024-09-14 22:55:57
  1. append 创建一个列表,它不会修改现有列表。
  2. 这是因为一般来说,Scheme(以及本例中的 Racket)是一种更喜欢函数式风格的语言。
  3. 您可以使用 set! 来更接近——但即使这样也会让您失望,因为它只会修改本地绑定。
  4. 请注意,特别是在 Racket 中,列表是不可变的,因此没有任何东西可以更改列表。
  5. 此外,即使您可以通过这种方式修改列表,这也是累积长列表的一种非常低效的方法,因为您必须重复扫描整个列表。
  6. 最后,如果您在这个级别遇到问题,那么我强烈建议您查看 HtDP
  1. append creates a new list, it does not modify an existing one.
  2. This is because in general, Scheme (and Racket in this case) is a language that prefers functional style.
  3. You could get somewhat closer with a set! -- but even that will disappoint you since it will modify only the local binding.
  4. Note that in Racket in particular, lists are immutable, so there's nothing that can change a list.
  5. 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.
  6. Finally, if you have issues at this level, then I strongly recommend going over HtDP
岁月苍老的讽刺 2024-09-14 22:55:57

(append foo bar) 返回 foobar 的串联。它不会更改 foobar

(append foo bar) returns the concatenation of foo and bar. It doesn't change either foo or bar.

骑趴 2024-09-14 22:55:57

您必须使用 set! 更新 currVal 的值。你的例子应该有

(set! currVal (append currVal (list carVal))
(display currVal)

You have to update the value of currVal with set!. Your example should have

(set! currVal (append currVal (list carVal))
(display currVal)
很糊涂小朋友 2024-09-14 22:55:57

您确实需要考虑您正在寻找的确切功能。

如果您想就地改变引用列表,那么您必须执行相当于追加的操作! (如其他答案中所述)。但这是危险的,因为您可能有其他代码依赖于列表是不可变的,如果您打算这样做,您的过程需要有一个!最终标记出这种危险。

以更实用的方式,对您想要做的事情的一个简单的近似是:

(define (populateValues carVal currVal)
 (let ((ll (append currVal (list carVal))))
   (display ll)
   ll))

请注意,它会创建一个新列表,进行追加,显示结果,然后将新列表作为值返回。如果您无权访问中间值,这是一种有用的调试技术:绑定到变量,显示或记录它,然后返回它。

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.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文