过程(Procedure)在Scheme语言中,过程相当于C语言中的函数,不同的是Scheme语言过程是一种数据类型,这也是为什么Scheme语言将程序和数据作为同一对象处理的原因。如果我们在Guile提示符下输入加号然后回车,会出现下面的情况:
1
2
| guile> +
#<primitive-procedure +>
|
这告诉我们"+"是一个过程,而且是一个原始的过程,即Scheme语言中最基础的过程,在GUILE中内部已经实现的过程,这和类型判断一样,如boolean?等,它们都是Scheme语言中最基本的定义。注意:不同的Scheme语言实现环境,出现的提示信息可能不尽相同,但意义是一样的。
define不仅可以定义变量,还可以定义过程,因在Scheme语言中过程(或函数)都是一种数据类型,所以都可以通过define来定义。不同的是标准的过程定义要使用lambda这一关键字来标识。
Lambda关键字Scheme语言中可以用lambda来定义过程,其格式如下:
(define 过程名 ( lambda (参数 ...) (操作过程 ...)))
我们可以自定义一个简单的过程,如下:
1
| (define add5 (lambda (x) (+ x 5)))
|
此过程需要一个参数,其功能为返回此参数加5 的值,如:
下面是简单的求平方过程square的定义:
1
| (define square (lambda (x) (* x x)))
|
与lambda相同的另一种方式在Scheme语言中,也可以不用lambda,而直接用define来定义过程,它的格式为:
(define (过程名 参数) (过程内容 …))
如下面操作:
1
2
3
4
| (define (add6 x) (+ x 6))
add6
#<procedure: add6 (x)> 说明add6是一个过程,它有一个参数x
(add6 23) => 29
|
再看下面的操作:
1
2
3
4
5
6
7
8
9
| guile> (define fun
(lambda(proc x y)
(proc x y)))
guile> fun
#<procedure fun (proc x y)>
guile> (fun * 5 6)
30
guile> (fun / 30 3)
10
|
更多的过程定义上面定义的过程fun有三个参数,其中第一个参数proc也是一个操作过程(因为在Scheme语言中过程也是一种数据,可以作为过程的参数),另外两个参数是数值,所以会出现上面的调用结果。
1
2
3
4
5
6
7
| guile> (define add
(lambda (x y)
(+ x y)))
guile> add
#<procedure add (x y)>
guile> (fun add 100 200)
300
|
继续上面操作,我们定义一个过程add,将add作为参数传递给fun过程,得出和(fun + 100 200)相同的结果。
1
2
| guile> ((lambda (x) (+ x x)) 5)
10
|
上面的 (lambda(x) (+ x x)) 事实上是简单的过程定义,在后面直接加上操作参数5,得出结果10,这样实现了匿名过程,直接用过程定义来操作参数,得出运算结果。
通过上面的操作,相信你已初步了解了过程的用法。既然过程是一种数据类型,所以将过程作为过程的参数是完全可以的。以下过程为判断参数是否为过程,给出一个参数,用 procedure? 来判断参数是否为过程,采用if结构(关于if结构见下面的介绍):
1
2
3
4
5
6
7
8
9
| guile> (define isp
(lambda (x)
(if (procedure? x) 'isaprocedure 'notaprocedure)))
guile> isp
#<procedure isp (x)>
guile> (isp 0)
notaprocedure
guile> (isp +)
isaprocedure
|
上面的过程就体现了Scheme语言的参数自省(辨别)能力,'0'是数字型,所以返回notaprocedure;而'+'是一个最基础的操作过程,所以返回isaprocedure。
过程的嵌套定义在Scheme语言中,过程定义也可以嵌套,一般情况下,过程的内部过程定义只有在过程内部才有效,相当C语言中的局部变量。
如下面的代码的最终结果是50:
1
2
3
4
5
6
| (define fix
(lambda (x y z)
(define add
(lambda (a b) (+ a b)))
(- x (add y z))))
(display (fix 100 20 30))
|
此时过程add只在fix过程内部起做用,这事实上涉及了过程和变量的绑定,可以参考下面的关于过程绑定(let,let* 和letrec)的介绍。
过程是初学者难理解的一个关键,随着过程参数的增加和功能的增强,过程的内容变得越来越复杂,小括号也会更多,如果不写出清晰的代码的话,读代码也会成为一个难题。 |