🌳应用序和正则序
有以下代码
1
2
3
4
#lang sicp
(define (square x) (* x x))
(define (sum-of-squares x y) (+ (square x) (square y)))
(define (f a) (sum-of-squares (+ a 1) (* a 2)))
什么是应用序/Application order
定义是:先求值参数,后应用
当解释器看到一个组合式(函数调用)的时候,他会把所有的操作数,也就是参数,都计算出具体的值,然后代入到过程中去
比如
1
2
3
4
5
6
(f 5) ;;->
(sum-of-squares (+ 5 1) (* 5 2));; ->
(sum-of-squares 6 10);; (在代入前,先算出了 6 和 10) ->
(+ (square 6) (square 10));; ->
(+ 36 100);; ->
136
这也是现在主流的语言 python, java 等求值方式
什么是正则序/Normal order
定义是:先完全展开,然后规约
其实就是遇到参数,先不求值.“展开”仅仅是指把函数调用替换为函数体,并将形参替换为原封不动、未求值的实参表达式,等需要这个参数的时候,再去求值
这是一种偷懒的方式,但缺点是会出现重复计算某一个表达式
案例:
1
2
3
4
5
6
7
(f 5);; ->
(sum-of-squares (+ 5 1) (* 5 2));; (不求值,直接代入) ->
(+ (square (+ 5 1)) (square (* 5 2)));; (继续展开 square) ->
(+ (* (+ 5 1) (+ 5 1)) (* (* 5 2) (* 5 2)));;(直到遇到基本的乘法 *,才开始真正计算) ->
(+ (* 6 6) (* 10 10)) ;;->
(+ 36 100) ;;->
136
但这里 (+ 5 1)被计算了两次
检测机器是正则序还是应用序
SICP 的练习 1.5 中,Ben Bitdiddle 发明了一个巧妙的测试,用来检测解释器使用的是应用序还是正则序
1
2
3
4
5
6
7
8
9
10
11
#lang sicp
(define (p) (p))
(define (test x y)
(if (= x 0)
x
y))
(test 0 (p))
我对 (test 0 (p)) 这个练习的分析有点问题。 我看正则序的定义是先完全展开而后规约,所以,我觉得 (test 0 (p)),会把test,p两个运算符展开,在对p展开的时候,会无限循环。所以正则序也会实现机器陷入死循环的停滞状态
在正则序中,“展开”仅仅是指把函数调用替换为函数体,并将形参替换为原封不动、未求值的实参表达式,而不是无脑地向下递归展开所有的参数 。
1
2
3
4
5
6
7
;;正则序下
(test 0 (p)) ;;->
;;参数原封不动代入
(if (= 0 0)
0
(p))
在正则序中,传入的实际参数只有在有需要时才会被求值,因此,在使用正则序的解释器里运行 (test 0 (p)) 时, 0 和 (p) 都不会立即被求值,当解释进行到 if 语句时,形式参数 x 的实际参数(也即是 0)会被求值(求值结果也是为 0 ),然后和另一个 0 进行对比((= x 0)),因为对比的值为真(#t),所以 if 返回 0 作为值表达式的值,而这个值又作为 test 函数的值被返回。
This post is licensed under CC BY 4.0 by the author.