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;;结果

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容