我最近一直在学习Scheme,在教程中我发现了一个名为append
的程序(define append
(lambda (ls1 ls2)
(if (null? ls1)
ls2
(cons (car ls1) (append (cdr ls1) ls2)))))
我不明白这背后的逻辑但是理解它将第一个列表的成员逐个附加到第二个列表。任何人都可以解释我程序的最后一行吗? 这两个论点的含义是什么意思?
我跑了
(trace (append '( a b c) '(d e f)))
最后以
结束[Entering #[compound-procedure 4 append]
Args: (a b c)
(d e f)]
[Entering #[compound-procedure 4 append]
Args: (b c)
(d e f)]
[Entering #[compound-procedure 4 append]
Args: (c)
(d e f)]
[Entering #[compound-procedure 4 append]
Args: ()
(d e f)]
[(d e f)
<== #[compound-procedure 4 append]
Args: ()
(d e f)]
[(c d e f)
<== #[compound-procedure 4 append]
Args: (c)
(d e f)]
[(b c d e f)
<== #[compound-procedure 4 append]
Args: (b c)
(d e f)]
[(a b c d e f)
<== #[compound-procedure 4 append]
Args: (a b c)
(d e f)]
;The object (a b c d e f), passed as an argument to procedure-lambda, is not a procedure.
如果您解释如何阅读此跟踪结果,那将是gud!
答案 0 :(得分:2)
首先你使用跟踪错误。您需要在要跟踪的过程上调用它,而不是表达式。像这样:
(trace append)
最后一行是跟踪抱怨它无法恍惚列表(a b c d e f)
。您看到的跟踪输出来自之前调用trace
完成的权限!
现在如何阅读..每个条目看起来像:
[Entering #[compound-procedure 4 append]
Args: (a b c)
(d e f)]
这意味着与(append '(a b c) '(d e f))
相同。以下是来自同一实例的退出跟踪:
[(a b c d e f)
<== #[compound-procedure 4 append]
Args: (a b c)
(d e f)]
这表示它返回(a b c d e f)
,呼叫为(append '(a b c) '(d e f))
。
请注意,这两者并不是相继出现的。原因是cons
步骤需要等待递归步骤首先执行(b c d e f)
。所有列表都是从头到尾制作的。
如果我们致电(append '(a b c) '(d e f))
,就会发生这种情况:
(append '(a b c) '(d e f)) ; ==>
(cons 'a (append '(b c) '(d e f))) ; ==>
(cons 'a (cons 'b (append '(c) '(d e f)))) ; ==>
(cons 'a (cons 'b (cons 'c (append '() '(d e f))))) ; <==
(cons 'a (cons 'b (cons 'c '(d e f)))) ; <==
(cons 'a (cons 'b '(c d e f))) ; <==
(cons 'a '(b c d e f)) ; <==
'(a b c d e f) ; result
实际上,参数表达式的计算结果为值,但我在这里引用它们,以便您可以将它们粘贴到REPL中并在所有行上得到相同的结果。
此处的评估顺序与您的跟踪中的评估顺序相同。
答案 1 :(得分:1)
这一行:
(cons (car ls1) (append (cdr ls1) ls2))
只需将第一个列表中的当前元素添加到将第一个列表的其余部分附加到第二个列表的结果中。为了理解为什么这最终有效,看看当第一个列表中的所有元素都已被强制转换时递归如何结束,我们最后将第二个列表放在最后:
(if (null? ls1) ls2
这就是它的运作方式!正如您所见,这是一个递归过程。