define 的一般形式是:
(define (desired-name-of-procedure item-1 item-2 item-3 ... item-n)
(; what to do with the items))
解释define 行为的另一种方式是“组合方式”和“抽象方式”。
[A]组合方式简单来说:
语法(item-1 item-2 item-3 ... ... item-n)是Scheme(和一般的Lisp)提供的基本组合方式。
- 所有代码都是使用上述模式表示的列表
- 第一个(最左边的)项始终被视为运算符
- 括号强制应用运算符...最左边的项目需要接受所有后面的项目,作为参数
[B] 抽象手段很简单;一种命名事物的方法。
一个示例将演示这一切如何融入define 原语的概念...
示例——以自下而上的方式到达define
考虑这个表达式:
(lambda (x y) (* x y))
用简单的英语,上面的表达式翻译为“创建一个接受两个参数并返回其乘积的值的nameless过程”。请注意,这会生成一个 nameless 过程。
更准确地说,就组合方式而言,Scheme 为我们提供了关键字lambda 作为创建用户定义过程的原始运算符。
最左边的项目--lambda--作为参数传递项目(x y) 和(* x y),并且操作员应用程序规则强制lambda 对这些项目做一些事情。
lambda 在内部定义的方式导致它解析列表(x y),并将x 和y 作为参数传递给列表(* x y),lambda 假定这是用户的定义遇到参数x 和y 时该怎么做。分配给x 和y 的任何值都将按照(* x y) 规则进行处理。
输入,抽象的手段...
假设我想在我的程序的几个地方引用这种类型的乘法,我可能会像这样调整上面的 lambda 表达式:
(define mul-two-things (lambda (x y) (* x y)))
define 将 mul-two-things 和 lambda 表达式作为参数,并将它们“绑定”在一起。现在 Scheme 知道 mul-two-things 应该与一个过程相关联,以获取两个参数并返回它们的乘积。
事实上,命名过程的要求非常普遍,并且提供了如此强大的表达能力,Scheme 提供了一个看起来更简洁的快捷方式。
就像@oscar-lopez 所说,define 是Scheme 提供的“特殊形式”,用于命名事物。而就Scheme的解释器而言,以下两个定义是相同的:
(define (mul-two-things x y) (* x y))
(define mul-two-things (lambda (x y) (* x y))