Scheme 编程/过程
到目前为止,我们已经使用了许多内置的 Scheme 过程(例如+, *,等等),但我们还没有看到如何定义我们自己的。过程是使用lambda形式创建的。这里有一个简单的例子
> (lambda (x) (* x x))
#<procedure>
评估 lambda
形式会返回一个过程对象,我们可以像对待任何其他值一样对待它。但是,与我们一直在使用的内置过程不同,这个过程缺少一些重要的东西——一个名字。因此,用 lambda 构造的过程被称为“匿名”;如果我们想要应用它们,我们必须将 lambda 表达式写成应用的运算符
> ((lambda (x) (* x x)) 4)
16
这是如何工作的?正如我们在前面章节中所看到的,我们通过首先评估运算符(这里它是 (lambda (x) (* x x))
)和操作数来评估过程对某些参数的应用。我们的 lambda 表达式评估为一个(匿名)过程,它接受一个参数,x,它返回的值是x的平方。应用于值 4,这个过程返回 16。
只使用匿名过程编写程序是不切实际的——尽管并非不可能。即使是相对简单的程序,如果我们必须为每个运算符编写 lambda 表达式,而不是使用方便的名称,也会变得难以忍受地复杂。由于过程是值,我们可以使用define为它们命名,就像我们对任何其他值一样
> (define square (lambda (x) (* x x)))
> (square (square 2))
16
在这里,我们将 square
定义为表示过程 (lambda (x) (* x x))
。一旦完成,我们就可以使用square作为我们喜欢的任何地方的过程。Scheme 不区分内置过程和新定义的过程,因此过程定义是 Scheme 程序员扩展语言的关键方式。
每次我们想写一个过程时,都要写 (define <name> (lambda (<arg> ...) ...))
有点笨拙,所以 Scheme 提供了一个简写形式。我们也可以写下我们对square的定义如下
(define (square x)
(* x x))
这个简写形式的一般形式是
(define (<name> <arg> ...) <body>)
这个定义与具有显式lambda表达式的定义相同,但它打字更快一些。您将在 Scheme 代码中不断看到这种定义形式。
您还可以创建具有可变数量参数的过程
(define (sum . args)
(apply + args))
这将创建过程 sum,它的工作原理与本机 + 过程完全相同。
这与以下代码相同
(define sum (lambda args
(apply + args)))
请注意,args 参数周围没有括号,因此所有参数都将被放入名为 args 的一个列表中。
使用 lambda,如果您想有一个固定的参数,而其他参数是可选的,您可以使用不完整的列表
(define sum (lambda (first . rest)
(/ first (apply + rest))))
有了它,您可以创建具有可选参数的过程
(define (rational first . rest)
(let ((second (if (null? rest) 1 (car rest))))
(/ first second)))
这将创建一个过程,当没有提供第二个参数时评估 (/ first 1)
,或者评估 (/ first second)
。