Lisp的求值规则
有些例子以scheme为例,不过大多在lisp都是通用的
lisp几乎所有类型都可以被求值。
数据类型的值:
-
数的值就是它本身(它抽象概念上代表的那个数)。
-
字符串也对自身求值。
-
符号
|-如果被引用(quote)的话,就表示它本身。|-如果不被引用,就是 关联着这个符号的对象。
- 如:函数 它的值是一个过程,一个对参数进行相关运算的过程,或者具体点说,就像是数学上的函数的表达式,如
f(x,y)=x^2+y^2
等。
|-内部操作符(如+,-)就是相关的一系列机器代码。
- 如:函数 它的值是一个过程,一个对参数进行相关运算的过程,或者具体点说,就像是数学上的函数的表达式,如
-
列表
|-被引用,就是一个列表。|-不被引用,就是函数调用,它的值就是那个表达式的值。
一般的求值规则
为了方便,咱们称 由多个小表达式组成的叫组合式,小表达式叫子表达式。
一)对基础的函数调用求值(以(+ 2 3)
为例):
- 首先从左至右对实参求值。&在本例中,数对自身求值,所以实参的值分别是
2
跟3
。 - 实参的值传入以操作符命名的函数。&本例中,将
2
跟3
传给+
函数,返回5
。
二)对组合式求值 与上类似(跳过_):
- 求值该组合式的各个子表达式。
- 将最左边的子表达式(运算符)的值(通常是过程)应用于相应的实际参数(其他子表达式的值)。
说白就是,先表达式的各个成分自己求值,然后因为最左边的函数的值是过程需要实参,所以将表达式的实参的值传入函数,最后函数的值作为表达式的值。
一些特殊的求值规则
lisp的大多数用到的都是一般求值规则,但有时候也需要特殊的求值规则。
quote
这个大家都知道,就是 引用 ,简写 '
英文单引号,
它的求值规则就是什么也不做,接受一个实参,直接返回被引用的部分。
如:
> '(+ 1 2)
(+ 1 2)
条件
像cond,if
定义
像define...
正则序和应用序
其实我们上述所说的一般求值规则,它的求值顺序被称为应用序
与之对应的是正则序。
- 应用序就是先对参数求值,而后应用于函数。
- 正则序是先用将表达式完全展开,直到只包含基本运算符,然后在去求值。
就比如,我们定义一个函数,通过余弦定理来计算cosA的值。
; 以scheme为例
; a b c是三角形的三边
> (define (cosA a b c)
(/ (- (+ (square b)
(square c))
(square a))
(* 2 b c)))
例如(cosA (+ 1 2) 4 3)
#|
应用序
就是(+ 1 2) 4 3先求值,然后代入cosA表达式,
然后再求子表达式square的值。。。
重复上述过程,最后求值。
正则序
(cosA (+ 1 2) 4 3)
1.
(/ (- (+ (square 4)
(square 3))
(square (+ 1 2))
(* 2 4 3)))
2.
(/ (- (+ (* 4 4)
(* 3 3))
(* (+ 1 2) (+ 1 2)) <-这里,就比应用的多用个加法函数
(* 2 4 3)))
3.
然后就是计算。。
|#
可能我这个例子不是很直观,但我们都能知道 当复杂了的时候,我们要进行多次的外部函数调用,那样就重复运行了很多。
应用序或可以节省一些资源,这俩一般影响的只是过程、复杂度(空间时间),一般不影响结果。
我们解释器大多时候采用应用序进行求值,不过一些特殊语句是用正则序的。如if语句。
xxxx
补充
或许通过求 阶乘 来比较两个会很明显。
> (define (factorial n)
(if (= 1 n)
n
(* n (factorial (- n 1)))))
例如:
> (factorial 10)
3628800
如果 if 是应用序
(factorial 10)
(if (= 10 1) 1 (* 10 (factorial 9)))
(if (= 10 1) 1 (* 10 (if (= 9 1) 1 (* 9 (factorial 8)))))
...
...
(if (= 10 1) 1 (* 10 (if (= 9 1) 1 (* 9 40320))))
(if (= 10 1) 1 (* 10 362880))
(if (= 10 1) 1 3628800)
(3628800)
if 是正则序 (Scheme解释器是用正则序的)
(factorial 10)
(if (= 10 1) 1 (* 10 (factorial 9)))
(* 10 (factorial 9))
(* 10 (if (= 9 1) 1 (* 9 (factorial 8))))
(* 10 (* 9 (factorial 8)))
...
...
(* 10 (* 9 (* 8 (* 7 (* 6 (* 5 (* 4 (* 3 (* 2 (1))))))))))
...
...
(3628800)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通