我正在学习R5RS计划(来自PocketScheme),我发现我可以使用内置于Scheme的某些变体中的函数但不是全部:Append!
换句话说 - 破坏性地更改列表。
我对实际代码并不是那么感兴趣,只要理解一个人可以将列表作为函数(或向量或字符串)传递然后改变它的过程。
示例:
(define (append! lst var)
(cons (lst var))
)
当我使用上述方法时,我必须执行类似(define list (append! foo (bar))
的操作,我希望这些更通用。
答案 0 :(得分:5)
虽然允许变异,但在计划中强烈反对。 PLT甚至删除了set-car!
和set-cdr!
(尽管他们用set-mcar!
和set-mcdr!
“替换”了它们。但是,append!
中出现append!
的规范。这个append!
与你的有点不同。在SRFI中,实现可能,但不是必需来修改缺点单元以附加列表。
如果您想要保证的(define (my-append! a b)
(if (null? (cdr a))
(set-cdr! a b)
(my-append! (cdr a) b)))
来更改要附加到的列表的结构,您可能需要自己编写。这并不难:
a
为了保持定义简单,这里没有错误检查,但很明显,你需要传递一个长度至少为1 b
的列表,并且(最好)一个列表(任意长度) )a
。 set-cdr!
必须至少为长度1的原因是因为您无法在空列表中a
。
既然你对它的工作方式感兴趣,我会看看能不能解释一下。基本上,我们要做的是在列表cons
下方,直到我们到达最后一个(<last element> . null)
对,即a
。因此,我们首先通过检查null
中的cdr
来查看set-cdr!
是否已经是列表中的最后一个元素。如果是,我们使用my-append!
将其设置为我们要添加的列表,我们就完成了。如果没有,我们必须在cdr
a
上致电a
。每次我们这样做,我们都会接近{{1}}的末尾。由于这是一个变异操作,我们不会返回任何内容,因此我们不必担心将修改后的列表形成为返回值。
答案 1 :(得分:0)
在这个主题上投入2-3美分,总比迟到总好......
(1)使用Scheme 中的破坏性过程没有任何问题,而只有一个对被修改结构的引用。例如,通过单个引用有效地构建大型列表 - 并且在完成时,使得(现在可能不被修改)列表已知并从各种指示对象中引用。
(2)我认为APPEND!应该像APPEND一样,只是(可能)具有破坏性。 APPEND!应该期望任意数量的列表作为参数。每个列表,但最后一个列表可能是SET-CDR!'到下一个。
(3)APPEND的上述定义!本质上是来自Mac Lisp和Common Lisp的NCONC。 (和其他的lisps)。