2020-03-05lisp学习-4

27/ 为什么 Lisp 没有指针 (Why Lisp Has No Pointers)

一个理解 Lisp 的秘密之一是意识到变量是有值的,就像列表有元素一样。如同Cons对象有指针指向他们的元素,变量有指针指向他们的值。

;;可以把变量当成一个容器,可以装不同的东西。

28/ 函数copy-list接受一个列表,然后返回此列表的复本。新的列表会有同样的元素,但是装在新的Cons对象里:每个cons对象装在不同的容器中。

>(setf x '(a b c);;;定义变量x并赋值

y (copy-list x) );;;把容器x中得值,拷贝一份到容器y

(ABC);结果,返回最后运算值,此处为y的值

测验:

* (eql x y)

NIL
* (equal x y)

T

29/ 函数append返回任何数目的列表串接 (concatenation):它复制所有的参数,除了最后一个

* (append '(a b) '(c d) '(t y u) '(y i) '(5 6)  '(c d) 'e) ;;最后一个不为列表形式,其余为列表

(A B C D T Y U Y I 5 6 C D . E)
* (append '(a b) '(c d) '(t y u) '(y i) '(5 6)  '(c d) 'f);;;复制所有的参数,除了最后一个,若末位实参非列表,则?

(A B C D T Y U Y I 5 6 C D . F)

* (append '(a b) '(c d) );;;;复制所有列表内的参数,组成新列表.

(A B C D)

30 游程编码(run-length encoding)

* (defun n-elts (elt n);;;定义函数名及形参,此处elt为数据列表,非函数elt
  (if (> n 1);;;;若n大于1,真,否则,假
      (list n elt);;真,返回n 与elt组成新列表
      elt));;假,返回elt数据列表

作用:判断n值是否大于1,若真,则返回n与原列表作为实参组成的新列表;若假则返回原列表。N-ELTS举例如下

* (n-elts '(4 5 6) 9)

(9 (4 5 6))

* (defun compr (elt n lst) ;;定义函数名及形参,此处elt 为数据列表,n为计数器,初始值不应大于1
  (if (null lst) ;;判断列表是否为空,空则真,不空则假
      (list (n-elts elt n));;;真,继续执行n-elts 程序,返回新列表(n elt),n≤1,则(elt)
      (let ((next (car lst)));;假,定义变量next并赋lst列表的首值
        (if (eql next elt);;;判断变量值与数据列表值是否为相同对象,相同,真;不同,假;(实质是判断lst列表中相邻两值是否相同)
            (compr elt (+ n 1) (cdr lst));;真,循环执行compr,取n值+1,列表为首值后的新列表。
            (cons (n-elts elt n) ;;假,执行n-elts 程序,返回新列表(n elt);n≤1,则(elt),确定出cons新组列表返回的第一个值
                  (compr next 1 (cdr lst))))))) ;;;lst首值作为next,从第一个开始判断,首值后元素组成新列表作为lst,循环执行开始程序

compr举例:

*  (compr '( 3 5 7) 9 nil);;;;lst为空情况
((9 (3 5 7)));;返回elt与n组成的新列表(n不大于1则返回elt列表值)

* (compr 4 2 nil)

((2 4))

*  (compr 4 1 '(3 4 4 4 3 4 5))

(4 3 (3 4) 3 4 5)

*  (compr 4 0 '(3 4 4 4 3 4 5))

(4 3 (3 4) 3 4 5)

*  (compr 4 2 '(3 4 4 4 3 4 5))

((2 4) 3 (3 4) 3 4 5)

*  (compr 3 1 '(4 4 4 3 4 5))


* (defun compress (x) ;;定义函数名及形参
  (if (consp x);;;判断实参是否为列表,是,真;否,假
      (compr (car x) 1 (cdr x));;;;真,比较列表相邻两值是否相等,并统计出连续相同值得个数。取(car x)值到elt,n为1,(cdr x)到lst
      x));;;假,直接返回x值

COMPRESS函数举例:

* (compress '(1 1 1 0 1 0 0 0 0 人 人 人))

((3 1) 0 1 (4 0) (3 人))

* (compress '(1 1 1 0 1 0 0 0 0 1))

((3 1) 0 1 (4 0) 1)

过程分析:

(compress '(1 1 1 0 1 0 0 0 0 1));;x为 '(1 1 1 0 1 0 0 0 0 1)

执行:(if (consp x);;; (1 1 1 0 1 0 0 0 0 1)非空列表,真

执行:(compr (car x) 1 (cdr x)) 即(compr 1 1 (1 1 0 1 0 0 0 0 1));;compr (elt n lst)注意位置对应的变量名。elt存储了x列表第一个值,n赋值为1,lst存储了新列表(cdr x)

执行:(if (null lst)即(if (null (1 1 0 1 0 0 0 0 1)) ;;不空,假

不执行:(list (n-elts elt n));;;真

执行:(let ((next (car lst)))即(let ((next (car (1 1 0 1 0 0 0 0 1))));;假,取(x列表第二个值)lst列表首值存储到变量next

执行:(if (eql next elt)即(if (eql 1 1);;;比较变量中对象是否相同,elt中存储x列表第一个值(car x),next存储了lst列表第一个值(car lst)(即x列表第二个值)。实质是判断lst列表中,从第一个位置开始,相邻两值是否相同),相同,真;不同,假

执行:(compr elt (+ n 1) (cdr lst))即(compr 1 2 (1 0 1 0 0 0 0 1));;真,elt变量中存储的值仍为(x列表第一个值)1,n存储器中值增加1为(+ n 1)=2,lst列表更新为(cdr lst)为(1 0 1 0 0 0 0 1)新lst列表。

2执行:(if (null lst)即(if (null (1 0 1 0 0 0 0 1)) ;;不空,假

2不执行:(list (n-elts elt n));;;真

2执行:(let ((next (car lst)))即(let ((next (car (1 0 1 0 0 0 0 1))));;假,取(x列表第三个值)新lst列表首值存储到变量next

2执行:(if (eql next elt)即(if (eql 1 1);;;比较变量中对象是否相同,elt中存储列表第一个值(car x),next存储了新lst列表第一个值(car lst)(即x列表第三个值)。实质是判断lst列表中第一个值和第三个值是否相同),相同,真;不同,假

2执行:(compr elt (+ n 1) (cdr lst))即(compr 1 3 (0 1 0 0 0 0 1));;真,elt变量中存储的值仍为(x列表第一个值)1,n存储器中值增加1为(+ n 1)=3,新lst列表更新为(cdr lst)为(0 1 0 0 0 0 1) 新lst列表2。

3执行:(if (null lst)即(if (null (0 1 0 0 0 0 1)) ;;不空,假

3不执行:(list (n-elts elt n));;;真

3执行:(let ((next (car lst)))即(let ((next (car (0 1 0 0 0 0 1))));;假,取(x列表第四个值)新lst列表2首值存储到变量next

3执行:(if (eql next elt)即(if (eql 0 1);;;比较变量中对象是否相同,elt中存储列表第一个值(car x),next存储了新lst列表2第一个值(car lst)(即x列表第四个值)0。实质是判断lst列表中第一个值和第四个值是否相同),相同,真;不同,假

3不执行:(compr elt (+ n 1) (cdr lst));;真

3执行:(cons (n-elts elt n) 即(cons (n-elts 1 3) ;;假,执行n-elts 程序,返回新列表(n elt);n≤1,则(elt)。返回列表(3 1)并暂存到cons函数容器中,等待最终合成

3执行:(compr next 1 (cdr lst))))))) ;;;继续执行(compr 0 1 (cdr lst)),next(即x列表第四个值)中的0值做为新的elt,n赋值1,新lst列表2更新为(cdr lst)为(1 0 0 0 0 1) 新lst列表3。

4执行:(if (null lst)即(if (null (1 0 0 0 0 1)) ;;判断新lst列表3,不空,假

4不执行:(list (n-elts elt n));;;真

4执行:(let ((next (car lst)))即(let ((next (car (1 0 0 0 0 1))));;假,取(x列表第五个值)新lst列表3首值存储到变量next

4执行:(if (eql next elt)即(if (eql 1 0);;;比较变量中对象是否相同,elt中存储了列表第四个值0,next存储了新lst列表3第一个值(car lst)(即x列表第五个值)1。实质是判断lst列表中第四个值和第五个值是否相同),相同,真;不同,假

4不执行:(compr elt (+ n 1) (cdr lst));;真

4执行:(cons (n-elts elt n) 即(cons (n-elts 0 1) ;;假,执行n-elts 程序,返回新列表(n elt);n≤1,则(elt)。返回列表(0)并暂存到cons函数容器中,等待最终合成

4执行:(compr next 1 (cdr lst))))))) ;;;继续执行(compr 1 1 (cdr lst)),next(即x列表第五个值)中的1值做为新的elt,n赋值1,新lst列表3更新为(cdr lst)为(0 0 0 0 1) 新lst列表4。

5执行:(if (null lst)即(if (null (0 0 0 0 1)) ;;新lst列表4不空,假

5不执行:(list (n-elts elt n));;;真

5执行:(let ((next (car lst)))即(let ((next (car (0 0 0 0 1))));;假,取(x列表第六个值)新lst列表4首值存储到变量next

5执行:(if (eql next elt)即(if (eql 0 1);;;比较变量中对象是否相同,elt中存储x列表第五个值1,next存储了新lst列表4第一个值(carlst)(即x列表第六个值)0。实质是判断lst列表中第五个值和第六个值是否相同),相同,真;不同,假

5不执行:(compr elt (+ n 1) (cdr lst));;真

5执行:(cons (n-elts elt n) 即(cons (n-elts 1 1) ;;假,执行n-elts 程序,返回新列表(n elt);n≤1,则(elt)。返回列表(1)并暂存到cons函数容器中,等待最终合成

5执行:(compr next 1 (cdr lst))))))) ;;;继续执行(compr 0 1 (cdr lst)),next(即x列表第六个值)中的0值做为新的elt,n赋值1,新lst列表4更新为(cdr lst)为( 0 0 0 1) 新lst列表5。

6执行:(if (null lst)即(if (null (0 0 0 1)) ;;新lst列表5不空,假

6不执行:(list (n-elts elt n));;;真

6执行:(let ((next (car lst)))即(let ((next (car (0 0 0 1))));;假,取(x列表第七个值)新lst列表5首值存储到变量next

6执行:(if (eql next elt)即(if (eql 0 0);;;比较变量中对象是否相同,elt中存储x列表第六个值0,next存储了新lst列表5第一个值(car lst)(即x列表第七个值)0。实质是判断lst列表中第六个值和第七个值是否相同),相同,真;不同,假

6执行:(compr elt (+ n 1) (cdr lst));;真.;继续执行(compr 0 2 (cdr lst)),elt变量中存储的值为0(x列表第六个值),n存储器中值增加1为(+ n 1)=2,新lst列表5更新为(cdr lst)为( 0 0 1) 新lst列表6。

7执行:(if (null lst)即(if (null (0 0 1)) ;;新lst列表6不空,假

7不执行:(list (n-elts elt n));;;真

7执行:(let ((next (car lst)))即(let ((next (car (0 0 1))));;假,取(x列表第八个值)新lst列表6首值0存储到变量next

7执行:(if (eql next elt)即(if (eql 0 0);;;比较变量中对象是否相同,elt中存储x列表第六个值0,next存储了新lst列表6第一个值(car lst)(即x列表第八个值)0。实质是判断lst列表中第六个值和第八个值是否相同),相同,真;不同,假

7执行:(compr elt (+ n 1) (cdr lst));;真.;继续执行(compr 0 3 (cdr lst)),elt变量中存储的值为0(x列表第六个值),n存储器中值增加1为(+ n 1)=3,新lst列表6更新为(cdr lst)为( 0 1) 新lst列表7。

8执行:(if (null lst)即(if (null (0 1)) ;;新lst列表7不空,假

8不执行:(list (n-elts elt n));;;真

8执行:(let ((next (car lst)))即(let ((next (car (0 1))));;假,取(x列表第九个值)新lst列表7首值0存储到变量next

8执行:(if (eql next elt)即(if (eql 0 0);;;比较变量中对象是否相同,elt中存储x列表第六个值0,next存储了新lst列表7第一个值(car lst)(即x列表第九个值)0。实质是判断lst列表中第六个值和第九个值是否相同),相同,真;不同,假

8执行:(compr elt (+ n 1) (cdr lst));;真.;继续执行(compr 0 4 (cdr lst)),elt变量中存储的值为0(x列表第六个值),n存储器中值增加1为(+ n 1)=4,新lst列表7更新为(cdr lst)为(1) 新lst列表8。

9执行:(if (null lst)即(if (null (1)) ;;新lst列表8不空,假

9不执行:(list (n-elts elt n));;;真

9执行:(let ((next (car lst)))即(let ((next (car (1))));;假,取(x列表第十个值)新lst列表8首值1存储到变量next

9执行:(if (eql next elt)即(if (eql 1 0);;;比较变量中对象是否相同,elt中存储x列表第六个值0,next存储了新lst列表8第一个值(car lst)(即x列表第十个值)1。实质是判断lst列表中第六个值和第十个值是否相同),相同,真;不同,假

9不执行:(compr elt (+ n 1) (cdr lst));;真

9执行:(cons (n-elts elt n) 即(cons (n-elts 0 4) ;;假,执行n-elts 程序,返回新列表(n elt);n≤1,则(elt)。返回列表(4 1)并暂存到cons函数容器中,等待最终合成

9执行:(compr next 1 (cdr lst))))))) ;;;继续执行(compr 1 1 (cdr lst)),next(即x列表第十个值)中的1值做为新的elt,n赋值1,新lst列表8更新为(cdr lst)为(nil) 新lst列表9。

10执行:(if (null lst)即(if (null (nil)) ;;新lst列表9空,真

10执行:(list (n-elts elt n))即(list (n-elts 1 1));;;真,执行n-elts 程序,返回新列表(n elt);n≤1,则(elt)。返回列表(1),并暂存到cons函数容器中,等待最终合成。

;;;返回(1)到9

10不执行:(let ((next (car lst)));;

10不执行:(if (eql next elt);;

10不执行:(compr elt (+ n 1) (cdr lst));;真

10不执行:(cons (n-elts elt n)  (compr next 1 (cdr lst))))))) ;;;

9执行:(cons '(4 0) '(1)) ;;;返回8

( (4 0) 1)

6-8不执行:(cons (n-elts elt n)  (compr next 1 (cdr lst))))))) ;;返回到上层

5执行:(cons '(1) (cons '(4 0) '(1)) ) ;;;返回开始4

((1) (4 0) 1)

4执行:(cons '(0) (cons '(1) (cons '(4 0) '(1) )) ) ;;;返回开始3

( (0) (1) (4 0) 1)

3执行:(cons  '(3 1) (cons '(0) (cons '(1) (cons '(4 0) '(1) )) )) ;;;返回开始2

((3 1) (0) (1) (4 0) 1)

2不执行:(cons (n-elts elt n)  (compr next 1 (cdr lst))))))) ;;返回开始

不执行:(cons (n-elts elt n)  (compr next 1 (cdr lst))))))) ;;返回终值


总结:递归原理即确定解决问题的规则,每一层级按此规则解决问题(看做末端,得出返回值即认为此层程序执行完毕),并把每层计算的数值或nil或t返回,代入到上一层级,最终在顶层输出程序段的最终语句所指定的表达式值。(层层向下分拆逻辑关系,层层向上归纳返回值。

31/ elt函数,返回列表某个位置的值(elt  lst n),列表起始位置为0,依次往后累加

  (elt '(1 2 35 7 8 ) 4);;;返回列表第4位置的值

8;;结果

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容