clisp 学习笔记 2-列表
cons & atom & list
对于列表,应当如此抽象——
可以认为,cons 函数是做这样一件事——把两个对象结合成一个有两个元素的对象,使用 car 取第一个对象,使用 cdr 取其余对象。或者说,car 和 cdr 是两个指针。
这种 cons 表示法叫做箱子表示法(box),因为每一个 cons 对象用箱子表示。而列表,则是一连串箱子。
要注意的是,包含列表的列表叫做嵌套列表,否则叫平坦列表(flatlist),或者叫序列 sequence。
谓词 consp 判断元素是否 cons 对象。不是 cons 对象的就是 atom。列表是特殊的,空列表等同于 nil,它也是 atom,而非空列表是 cons。
因此,我们可以定义 listp——
1 |
|
equal & eql
每次调用 cons(和 list),lisp 都会分配一块新的内存给两个指针,因此使用同样的参数调用两次 cons,其数值上一样,但是并非是同一个对象。
1 |
|
可见,eql 比较是否是一个对象,equal 比较是否数值相同。就像 python 里 is 和==的关系,前者是判断是否是一个对象——在内存里是同一块地址,后者判断是否数值相同。
指针?不存在的
lisp 只有引用,没有指针。
1 |
|
建立列表
复制列表——copy-list 和 copy-tree
1 |
|
其他存取函数
其他存取函数都是通过 car 和 cdr 定义的,nth 和 nthcdr 分别找到第几个位置的 car 和 cdr。nth 相当于是 (car (nthcdr index lst))
它们都是零索引的,即从 0 开始计数。
同时,还有从 fitst 到 tenth,取相对应位置的对象。它们是非零索引的。如,(second x) 相同于 (nth 1 x)
1 |
|
映射函数(mapping function)
所谓映射函数,就是对列表元素都进行函数调用,将结果作为一个列表返回。最常用的是 mapcar。
此外,maplist 和 mapcar 接受一样的参数,但是 maplist 对每一个 cdr(包括该 cons 本身)进行调用,最终返回结果的 list。
1 |
|
列表模拟的数据结构
这些数据结构都是 cons 对象,它们的操作函数都是共同的,你要抽象成什么结构,就用什么函数。
树(tree)
cons 对象可以想象成二叉树,car 代表左子树,cdr 代表右子树。
比如对 (a (b c) d),其结构可以想象为——
substitute 接受三个参数,新值,原值,一个序列,它会返回这样一个副本,其中将序列里的所有原值变为新值,要注意的是,这里的原值,新值等,是按 car 找的。
subst 则对树起作用,即它遍历所有 atom 而非原列表的所有 car。
1 |
|
集合(set)
集合,同数学或 python 中的 set。
它有 member 函数,测试一个元素是否在集合内,如果是,则返回从这个元素开始的部分。至于为什么这么用,我还不知道。
1 |
|
member 同时有 test 和 key 参数,test 参数表明使用什么函数进行测试,key 参数是首先对元素进行处理的函数,简单来说,member 对 set 的每一个元素先用 key 进行转换,然后用 test 对转换后的元素和接受的值进行测试,成功则结束函数,返回此时的 cdr。
1 |
|
member-if 函数则是测试是否有元素满足一个谓词。
1 |
|
adjoin 函数可以认为是 set 的添加,只有在 set 中无此元素,才添加它。它是 cons 的变种
1 |
|
然后是并集 (union)、交集 (intersection) 以及补集 (complement),它们是由函数 union 、 intersection 以及 set-difference 实现的。这个不用多说了。
序列(sequence)
序列可以认为是一系列有特定顺序的对象(虽然是一串 cons 序列,或者说链表模拟的)。
length 函数,返回序列的长度。这个不用解释,都有。
subseq 函数,返回子序列。第一个参数为序列第二个参数是第一个开始引用的元素的 index,第三个参数(可选)是第一个不引用进来的元素的 index。
subseq 是复制还是引用?复制,这其实是显然的 www 因为从中间抠出来一个子序列,最后一个 cons 元素的 cdr 必须(设置)为 nil,所以有副作用,所以应当是复制。
1 |
|
reverse 函数返回颠倒的序列。注意,它是引用的!
1 |
|
**sort **函数。sort 是破坏性的,它有副作用——更改原序列。
1 |
|
every 和 some 函数接受序列和一个谓词,前者检测是否所有元素都符合谓词,后者则检测是否有些元素符合谓词。
1 |
|
栈
push 和 pop 函数,再熟悉不过了,要注意的是,它 push 和 pop 在 cons 对象最前而非最后。
1 |
|
使用 push 定义 reverse——
1 |
|
正如 adjoin 是 cons 的变种,pushnew 是 push 的变种,只有栈中没有该元素才入栈。
点状列表(dotted list)
点状列表就是 cdr 为 atom 且不为 nil 的列表。
1 |
|
关联列表(assoc-list)
关联列表就像 python 的字典,它容易表示映射(mapping)。它使用点状列表来表示。
assoc 函数用来取……键值对?它也有 key 和 test 参数。同时,也有 assoc-if。
1 |
|
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 协议 ,转载请注明出处!