Skip to content

Latest commit

 

History

History
111 lines (86 loc) · 3.65 KB

assignment.md

File metadata and controls

111 lines (86 loc) · 3.65 KB

赋值

赋值其实是一个被大家漠视了的概念,简单的赋值表达式如 x = 3 然后再次赋值 x = 4 这两个x还是同一个x吗?当然这里面涉及到"同一"和“变化”这样的哲学问题,已经超出了讨论的范畴。

但我想说的是,赋值这个操作实际上是为程序引入了时间的概念, 以赋值操作为分界线,事务已经发生了变化。 事实上碰到的各种并发问题的根源就在于赋值,函数式编程就不存在并发问题(当然,函数式编程会有自己的问题, 比如随机数生成过程)。

lisp中的赋值操作是 set!

(define a 3)

(set! a 4)

赋值之后,a的值为4。

有了赋值后,我们可以写出这样一个计数器:

(define (count n)
  (let ((value n))
    (lambda ()
      (set! value (+ 1 value))
      value)))
(define a (count 0))
(a)
(a)

这和我们之前求阶乘的程序有了根本性的不同

(define (fact n)
  (if (< n 2)
      n
      (* n (fact (- n 1)))))

(fact 5)
(fact 5)

阶乘程序无论调用多少次,只要输入相同,结果就一样,也就是具有“幂等性”。而这里的计数器有了自己的状态,每次调用的结果都不一样,这也就是赋值带来的变化。

引入了赋值之后,之前表达式求值的代换模型就不再适用了,于是引入了新的模型也就是环境模型。

所谓的环境就是一个个键值对,在其中能找到某个name对应的value。

在环境模型下,过程的定义是在环境中加入了以过程名为名,过程体为值的键值对。也即

(define (name arg) body)

是在环境中加入了这样一个键值对: name: (lambda (arg) body)

而过程的求值,是新生成一个过程形参和实参对应的框架,并链接到过程定义的初始环境上,在这个新的环境上求解过程体的过程。

考虑下面一段程序

(define (sum x y) (+ x y))

(sum 3 4)

(sum 4 5)

首先,有一个全局环境E0,里面包含+、-、*、/、3、4等的定义,这是解释器已经给我们生成好了的环境。

          -------------------------
          |   +: +, 3:3 , 4: 4 | 
          -------------------------

过程定义之后,环境变为 E1 ------------------------- | +: +, 3:3 , 4: 4 | ------------------------- / /

| sum: (lambda () (+ x y)) |

执行 (sum 3 4)时,环境变为 E2

           -------------------------
          |   +: +, 3:3 , 4: 4 | 
          -------------------------
           /                     \
          /                       \

| sum: (lambda () (+ x y)) | | x = 3, y = 4 | (F1)


在此环境下,求值sum的过程体 (lambda () (+ x y)), 即(+ x y), 结果为7。

执行(sum 4 5)时,环境变为 E3

           -------------------------
          |   +: +, 3:3 , 4: 4     | 
          --------------------------
           /                     \
          /                       \

| sum: (lambda () (+ x y)) | | x = 4, y = 5 | (F2)


在此环境下,求值sum的过程体 (lambda () (+ x y)), 即(+ x y), 结果为9。

这也就是两次函数调用的x和y互不影响的原因,因为求值时生成了两个独立的框架。

赋值操作改变了框架中变量的值,在新的环境中求解表达式即可。