我现在正在学习 Guile Scheme,在文档中我突然遇到了以下结构:
((lambda args (display args)) 42)
=> (42)
这让我陷入了循环;在此之前,我一直认为形式参数总是包含在列表中:
((lambda (args) (display args)) 42)
=> 42
我想知道何时使用此变体,以及它与可变参数数量的点表示法有何不同。具体来说,以下两个变体有什么区别:
((lambda args (display args)) 1 2 3) => (1 2 3)
((lambda (. args) (display args)) 1 2 3) => (1 2 3)
是否有我需要注意的区别——也许是更复杂的例子——是否有任何理由偏爱一个而不是另一个?
不同之处在于此版本接收一个名为 args
的参数,当您确切知道lambda
形式预期的实际参数数量时很有用:
(lambda (args) (display args))
此版本接收一个(可能为空的(参数列表,称为 args
,当您期望lambda
形式的参数数量可变时很有用:
(lambda args (display args))
以下两个版本之间应该没有区别,但并非所有解释器都会接受第二个版本,因为它缺少点之前的部分(因此应避免(:
(lambda args (display args))
(lambda (. args) (display args))
当您要指定lambda
表单具有一个或多个必需参数(点左侧的符号(和零个或多个可选参数的列表(点右侧的单个符号(时,以下版本非常有用:
(lambda (mandadory1 mandatory2 . optional) (display mandatory1))
这让我陷入了循环;在此之前,我一直认为形式参数总是包含在列表中:
请注意,像(a . args)
和(a b . args)
之类的东西也不是真正的列表。 (a . args)
是一对,其中car
是符号a
,cdr
是符号args
。 (a b . args)
是一对,其中car
是符号a
,cdr
是(一对,其中car
是符号b
,cdr
是符号args
(。有一段时间它看起来有点像一个列表,有a
和b
等等,但由于它不以 null/空列表结尾,所以它不是一个真正的列表。像这样的结构通常被称为不正确的列表。如果你愿意,你可以在这里或其他地方阅读一些关于点线对符号的信息......
对于(. args)
,我可能会说"这是一对,其中cdr
是符号args
"。或者也许它会像"一对car
在哪里,cdr
args
"。无论哪种方式,它都没有多大意义,而且,正如Chris Jester-Young所说,它并不是真正有效的Scheme。
所以,像(a b . args)
这样的东西只是常规的点对表示法,用于将不为空的东西放在最后cdr
中。如果 Scheme 中的形式参数事物可以是那些不正确的列表之一,也可以是一个正确的列表,或者只是一个符号,那么形式参数事物的定义必须是这样的:形式参数事物必须是空值、符号或一对,其中car
是一个符号,cdr
是一个形式参数事物。
(我认为这是一种很酷的事情,它提供了一种将参数绑定到参数的相当优雅的方式。比如,你看形式参数-thing,如果它是一个符号,你就将参数列表绑定到它,如果它是一个对,你将参数的car
绑定到形式参数事物的cdr
,并在形式参数事物/参数cdr
上重复出现(哦,如果它是空的,你就完成了什么(。这让我觉得比Common Lisp的方式"如果car
中的符号是&rest
,你在那之后将其余的参数绑定到符号"的方式更漂亮。