这是一个扩展,不是标准方案的一部分。这个扩展在 MIT/GNU Scheme 中已经有很长一段时间了,其他一些实现也采用了它。
R7RS 规范未显示与 OP 发布的示例定义匹配的表单。最接近的匹配是 5.3 中的 this。变量定义:
-
(define (<variable> <formals>) <body>)
<Formals> 是零个或多个变量的序列,或者是一个或多个变量后跟一个空格分隔的句点和另一个变量的序列(如在 lambda 表达式中)。
有问题的定义是:
(define ((function-name arg1) arg2) (body ...))
这里,(function-name arg1) 必须被视为一个变量才能匹配标准中的描述;但它不是变量,甚至不是标识符。
来自 3.1。变量、句法关键字和区域:
命名位置的标识符称为变量,并且被称为绑定到该位置。
值得指出的是,Hanson 和 Sussman 的书的附录 B 简要讨论了这种结构:
在 MIT/GNU 方案中,我们可以递归地使用糖来编写:
(define ((compose f g) x)
(f (g x)))
现在,在第 1 页。 MIT/GNU Scheme Reference Manual (11.1) 的第 17 节表明:
(define (name1 name2 ...)
expression
expression ...)
相当于:
(define name1
(named-lambda (name1 name2 ...)
expression
expression ...))
请注意,MIT/GNU 手册中显示的语法显示了 lambda:
lambda formals expr expr ... [扩展标准特殊形式]
这里,formals 被描述为“形参列表”,但请注意没有使用术语variable。术语变量在手册的其他地方使用,例如,在let 表单的描述中。
named-lambda 特殊形式描述:
named-lambda formals 表达式 表达式 ... [特殊形式]
named-lambda 特殊形式与 lambda 类似,只是 formals 中的第一个“必填参数”不是参数而是 结果过程的名称;因此 formals 必须至少有一个必需参数。该名称没有语义含义,但包含在过程的外部表示中,因此对调试很有用。在 MIT/GNU Scheme 中,lambda 被实现为 named-lambda,具有一个特殊的名称,意思是“未命名”。
所以,(define ((function-name arg1) arg2) (body ...)) 的定义可以改写为:
(define (function-name arg1)
(named-lambda ((function-name arg1) arg2) (body ...)))
根据手册提供的上述转换规则,由于形式参数列表已在 MIT/GNU 方案中进行了扩展,因此它不仅限于包含 变量。
然后可以使用相同的规则再次(递归)扩展最后一个结果:
(define function-name
(named-lambda (function-name arg1)
(named-lambda ((function-name arg1) arg2)
(body ...))))
由于named-lambda 与lambda 类似,即不同之处仅在于有一些额外的元数据与之关联,但语义相同,我们可以写出语义等价:
(define function-name
(lambda (arg1)
(lambda (arg2)
(body ...))))
这只是高阶过程的定义。因此,所讨论的符号只是便于定义高阶过程的语法糖。请注意,SRFI 201 旨在为其他 Scheme 实现提供此功能,并将其称为“高阶 define 形式”,以及“@ 的“柯里化”变体987654339@ 表格。”
回到Software Design for Flexibility附录B中的示例程序,可以看出如何使用这种句法糖巧妙地表达函数组合的思想。
(define ((compose f g) x)
(f (g x)))
这里,compose 是一个带有两个参数 f 和 g 的过程,它返回一个带有一个参数 x 的过程:
1 (user) => (define my-composition (compose square cube))
;Value: my-composition
1 (user) => (my-composition 2)
;Value: 64