在Scheme中向List添加元素

时间:2010-07-03 20:19:30

标签: list scheme racket

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

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

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

5 个答案:

答案 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)

  1. append创建列表,但不会修改现有列表。
  2. 这是因为一般来说,Scheme(以及本案例中的Racket)是一种更喜欢功能风格的语言。
  3. 你可以与set!稍微接近 - 但即使这样也会让你失望,因为它只会修改本地绑定。
  4. 请注意,特别是在Racket中,列表是不可变的,因此 nothing 可以更改列表。
  5. 此外,即使您可以通过这种方式修改列表,这也是累积长列表的一种非常低效的方式,因为您必须重复扫描整个列表。
  6. 最后,如果您在此级别遇到问题,我强烈建议您查看HtDP

答案 2 :(得分:2)

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

答案 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))

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