Program Structure 笔记2 (求值模型)
(作者:colinboy Email:cybbh@163.com) 2008.4.30 V2
(内容难免出现错误或一些专业词汇使用不当,只是个人笔记,能理解总体内容就好)
计算机程序设计非常简单,很多10岁小孩都能设计程序,但这仅仅限于程序规模非常小的时候,这门课程不是讲授如何使用一门特定的语言,也不是说服你相信scheme是最好的程序设计语言.
计算机抽象层次结构
------------------------------
应用程序
------------------------------
高级程序设计语言 (scheme)
------------------------------
低级程序设计语言 (C)
------------------------------
机器语言 (binary bits)
------------------------------
电路单元 (门)
------------------------------
晶体管
------------------------------
define (argue s)
(if (empty? s)
'()
(sentence (opposite (first s))
(argue (bf s)))))
(define (opposite w)
(cond ((equal? w 'like) 'hate)
((equal? w 'hate) 'like)
((equal? w 'wonderful) 'terrible)
((equal? w 'terrible) 'wonderful)
((equal? w 'great) 'awful)
((equal? w 'awful) 'great)
((equal? w 'terrific) 'yucky)
((equal? w 'yucky) 'terrific)
(else w) ))
在上面程序中,存在一个递归调用(recursive call),在argue函数中, argue又调用argue来完成操作.
(cond )操作是一种特殊形式(special form),其他的特殊形式还有(if ) (define ),它们不根据一般性的求值规则去计算每个参数的值.
形式(form)的意思可以等同与表达式(expression)
所以"特殊形式"是一种"特殊的表达式"!!!
2种求值规则: 应用序(applicative order) 和 正则序(normal order)
应用序的规则为:
1.计算每个实际参数表达式.
2.根据计算出来的实际表达式的值,调用函数.
正则序的规则为:
1.根据实际参数表达式调用函数,而不计算表达式.
2.如果函数为一个scheme原始内置函数(例如 + -),那么就先计算每个实际参数表达式的值,根据计算出来的值进行调用.
例如以下函数:
(define (g x) (* 3 x)) --> 定义函数g
(define (f a b) (+ (g a) b)) -->定义函数f
如果我们执行(f (+ 2 3) (- 15 6))
应用序的计算过程如下:
1. 计算(+ 2 3)和(- 15 6),返回值分别为5,9
2. 根据计算的表达式值5和9调用(f 5 9)
3. (f 5 9) --> (+ (g 5) 9)
4. 计算(g 5) ---> (* 3 5) --> 15
5. 计算 (+ 15 9) --> 24
6. 运算结果为24
正则序的计算过程如下:
1. 根据表达式调用f,转换为(+ (g (+ 2 3)) (- 15 6))
2. 上式中+为原始内置函数,所以需要计算每个表达式的值,计算(g (+ 2 3),g不为原始类型,所以(g 5)转换为(* 3 5) --> 15
3. 计算(- 15 6) --> 9
4. 计算(+ 15 9) --> 24
5. 运算结果为24
根据以上结果,发现不论是使用应用序求值还是用正则序求值,对于上述(f (+ 2 3) (- 15 6))运算结果都是一样的. 但是对于任何函数调用,结果都会一样吗??
什么是函数式程序设计?
函数是一个过程(procedure),每次我们使用相同的实际参数调用此函数的时候,它总会返回相同的值.
函数式程序设计应该避免依赖2种求值规则!
如果我们定义一个过程(random x),他会随机返回一个从0到 x之间的值.
(random 10) --> 5
(random 10) --> 3
(random 10) --> 8
每次我们使用相同的参数调用random时,它可能会返回不同的结果,那么random是一个函数么?? 恩,在函数式程序设计中当然不是!!! 那么如果我们在程序中使用了random过程,我们的程序设计将会依赖求值规则,这将不是函数式程序设计.
例如下面的函数:
(define (zero x) (- x x))
如果我们执行(zero (random 10))
使用应用序求值规则结果为0
但是使用正则序求值规则结果可能不为0,为什么呢??原因如下:
应用序求值过程:
1. 计算表达式(random 10),假设返回5.
2. 根据表达式值调用zero函数, (zero 5),
3. 计算(zero 5) --> (- 5 5) --> 0
正则序求值过程:
1. 根据表达式调用zero.
2. 转换为(- (random 10) (random 10)),假设第一个random返回9,第二个random返回6,那么结果为3.
如果我们使用函数式程序设计,那么我们不需要关心程序的执行顺序以及所使用的求值规则.
如果不遵守函数式程序设计规则,那么我们需要小心,因为很可能会出现上面例子中的情况.