上一章讲了向量、哈希表等比Lisp中较常用的数据结构。就如今的Common Lisp而言,的确选择很多,而过去却只有列表(list)这一个选项,so~
当然历史原因只是其一(话说能在历史中被选择的总有其合理之处),就当前通常可见的场景下,List也是一个不错的选择,其实用性早已被时间所证明(有点像数学啊,很多公理都早已被确定~)。所以,了解List,知道选择List的优劣还是很有必要的。
跳过一段"花非花"的论断,让我们直接进入叫做"cons cells"的东东(算是list的原型吧,无需深入,现在都用新的定义方式了):
我们用cons来定义、创建这个结构:
(cons 1 2) ==> (1 . 2)
一些基本的动作:
(car (cons 1 2)) ==> 1
(cdr (cons 1 2)) ==> 2
(defparameter *cons* (cons 1 2))
*cons* ==> (1 . 2)
(setf (car *cons*) 10) ==> 10
*cons* ==> (10 . 2)
(setf (cdr *cons*) 20) ==> 20
*cons* ==> (10 . 20)
合并、嵌套:
(cons 1 nil) ==> (1)
(cons 1 (cons 2 nil)) ==> (1 2)
(cons 1 (cons 2 (cons 3 nil))) ==> (1 2 3)
用直观的图形来表示:
原子状态:
模拟个(1 2 3)列表:
当当当...隆重引出我们的列表专用key:List
(list 1) ==> (1)
(list 1 2) ==> (1 2)
(list 1 2 3) ==> (1 2 3)
对应的一些基本动作:
(defparameter *list* (list 1 2 3 4))
(first *list*) ==> 1
(rest *list*) ==> (2 3 4)
(first (rest *list*)) ==> 2
列表还能轻松hold住各种类型的元素:
(list "foo" (list 1 2) 10) ==> ("foo" (1 2) 10)
看起来就像这个样子:
原则上,如果需要,列表可以无限扩展任意深度。
关于列表,Lisp为其配套了一大堆功能性函数,在这儿就不一一阐述,取其典型:append
(append (list 1 2) (list 3 4)) ==> (1 2 3 4)
直观图:
(这图不错啊~)
细心的人可能已经发现,似乎并非是一个全新的列表啊,被你发现了~
(defparameter *list-1* (list 1 2))
(defparameter *list-2* (list 3 4))
(defparameter *list-3* (append *list-1* *list-2*))
*list-1* ==> (1 2)
*list-2* ==> (3 4)
*list-3* ==> (1 2 3 4)
(setf (first *list-2*) 0) ==> 0
*list-2* ==> (0 4) ; as expected
*list-3* ==> (1 2 0 4) ; maybe not what you wanted
似乎符合发现,但不符合预期啊。这种关联是有适用场景的,从某种程度上节约了数据空间的成本。所以,使用的时候需要小心。
其实大部分对列表的操作函数其实是不破坏原表的,除非你写成这个样子:
(setf *list* (reverse *list*))
生成新列表对于确保粒子的原子性有帮助,不过对于空间就比较糟蹋了,如果对空间有需求的话,可以使用类似上面的语句来覆盖原表,达到空间复用的目的:
(defparameter *x* (list 1 2 3))
(nconc *x* (list 4 5 6)) ==> (1 2 3 4 5 6)
*x* ==> (1 2 3 4 5 6)
下面来看一个关于循环和结构共享的例子:
(defun upto (max)
(let ((result nil))
(dotimes (i max)
(push i result))
(nreverse result)))
(upto 10) ==> (0 1 2 3 4 5 6 7 8 9)
上面的代码创建了独立无外部关联的列表。对于数据空间共享,还有个小窍门:
*list-2* ==> (0 4)
*list-3* ==> (1 2 0 4)
(setf *list-3* (delete 4 *list-3*)) ==> (1 2 0)
*list-2* ==> (0)
如果上面的delete改用remove的话就不会出现串联同步修改的问题了。
有无损的函数,自然就会有会损坏原表的,在这种情况下,如果有必要,copy-list是一个不错的选择:
CL-USER> (defparameter *list* (list 4 3 2 1))
*LIST*
CL-USER> (sort *list* #'<)
(1 2 3 4) ; looks good
CL-USER> *list*
(4) ; whoops!
因为一些历史原因,我们还可以看到一些比较奇怪的表达式:
(caar list) === (car (car list))
(cadr list) === (car (cdr list))
(cadadr list) === (car (cdr (car (cdr list))))
(caar (list 1 2 3)) ==> error
(caar (list (list 1 2) 3)) ==> 1
(cadr (list (list 1 2) (list 3 4))) ==> (3 4)
(caadr (list (list 1 2) (list 3 4))) ==> 3
目前只要知道这些表达式的意思就可以了,最好别多用~
以下是一些基本的不完全的功能列表:
Function | Description |
LAST | Returns the last cons cell in a list. With an integer, argument returns the last n cons cells |
BUTLAST | Returns a copy of the list, excluding the last cons cell. With an integer argument, excludes the last n cells. |
NBUTLAST | The recycling version of BUTLAST; may modify and return the argument list but has no reliable side effects. |
LDIFF | Returns a copy of a list up to a given cons cell. |
TAILP | Returns true if a given object is a cons cell that's part of the structure of a list. |
LIST* | Builds a list to hold all but the last of its arguments and then makes the last argument the CDR of the last cell in the list. In other words, a cross between LIST and APPEND. |
MAKE-LIST | Builds an n item list. The initial elements of the list are NIL or the value specified with the :initial-element keyword argument. |
REVAPPEND | Combination of REVERSE and APPEND; reverses first argument as with REVERSE and then appends the second argument. |
NRECONC | Recycling version of REVAPPEND; reverses first argument as if by NREVERSE and then appends the second argument. No reliable side effects. |
CONSP | Predicate to test whether an object is a cons cell. |
ATOM | Predicate to test whether an object is not a cons cell. |
LISTP | Predicate to test whether an object is either a cons cell or NIL. |
NULL | Predicate to test whether an object is NIL. Functionally equivalent to NOT but stylistically preferable when testing for an empty list as opposed to boolean false. |
作为一种数据结构,可遍历也是list的基本特性,所以map类函数也都有对应的解决方案:
MAPCAR
(mapcar #'(lambda (x) (* 2 x)) (list 1 2 3)) ==> (2 4 6)
(mapcar #'+ (list 1 2 3) (list 10 20 30)) ==> (11 22 33)
MAPLIST 对应cdr
MAPCAR/MAPLIST 生成新的list
MAPCAN/MAPCON 生成组合的list
MAPC/MAPL 结果覆盖第一个list
跳过了很多描述性和观点性的东西(有些是晦涩,有些是暂不认同),至于具体的函数,用到时看看help,文档应该很容易覆盖吧。
其实,就总体而言,只要coder有好的代码风格,做到数据传递不被破坏(或者是预期的破坏),一切就都是浮云了。
(未完待续)
分享到:
相关推荐
common-lisp-the-language-second-edition.PDF
而《Practical Common Lisp》则被提及为解决这类问题的最佳参考书,因为它不仅告诉读者如何做,更重要的是展示给读者为什么要这样做,以及如何应用在实际编程中。 书中并非只有理论教学,也包含了许多实际的编程...
《Practical Common Lisp笔记》是一本深入探讨Common Lisp编程语言的实用教程。Common Lisp是一种功能强大的多范式编程语言,以其动态类型、宏系统和丰富的内置数据结构而闻名。这篇笔记详细记录了作者在学习过程中...
标题中的"emacs-lisp-intro-2.04.tar.gz"是一个典型的压缩文件名,它表明这个文件是一个关于Emacs Lisp的介绍性资料,并且版本号是2.04,格式为tar.gz。tar.gz是一种在Linux和Unix系统中常用的文件压缩格式,它先用...
标题:“实用Common.Lisp编程.pdf” 描述:“实用Common.Lisp编程.pdf,2011.10出版” 从这些信息中,我们可以提炼出几个关键的知识点: ### Common Lisp语言简介 Common Lisp是一种高级的、通用的、多范式的编程...
这本书是Lisp爱好者的宝贵资源,不仅因为它详细讲解了Common Lisp的语言特性,还因为它提供了丰富的示例和说明,帮助程序员理解和运用这门语言。 在Common Lisp语言中,符号(Symbols)是命名实体和变量的基础。...
《实用Common Lisp》是Apress出版社出版的一本深入探讨Lisp编程语言的书籍,特别强调其实用性。这本书以其精细的页面设计和清晰的印刷质量,非常适合打印阅读,以便于深度学习和理解Lisp的强大之处。 Lisp是一种...
cad-lisp-3-表操作.LSP.lsp
Provides practical advice for the construction of Common Lisp programs. Shows examples of how Common Lisp is best used. Illustrates and compares features of the most popular Common Lisp systems on ...
Common-Lisp-Actors, 通用Lisp的actor系统 这是一个简单且易于使用的Actor系统,在。设置需要波尔多螺纹。http://common-lisp.net/project/bordeaux-threads/ 2. 加载 actors.lisp 并开始使用它。 如果你有 Quick
ANSI Common Lisp 中文翻译版.pdf 此资源是 ANSI Common Lisp 的中文翻译版,涵盖了 Common Lisp 语言的基础知识和高级主题。该资源包含了 17 章节,从基础的列表、特殊数据结构、控制流程、函数、输入与输出、符号...
这本《Practical Common Lisp》之所以号称Practical,正是因为这本书大量介绍Common Lisp在现实世界中的各种应用方式,算是第一本「入世传教」的Common Lisp著作。《Practical Common Lisp》是目前最畅销的Common ...
If you’re interested in Lisp as it relates to Python or Perl, and want to learn through doing rather than watching, Practical Common Lisp is an excellent entry point. — Chris McAvoy, Chicago Python ...
Practical Common Lisp 学习lisp的入门书籍
3. **Web 开发**:尽管Common Lisp在Web开发领域不如Python或JavaScript那样流行,但它依然可以用于构建高性能的Web应用和服务。 4. **自然语言处理**:Common Lisp的灵活性使其成为处理自然语言的理想选择之一,...
AutoLisp源文件--标注高程.LSP
使用这样的工具时,用户应当谨慎处理,因为它涉及到对受保护的知识产权的操作,可能有法律风险。 总的来说,Lisp解密程序是一个技术含量高、需要对Lisp语言有深入理解的工具,它揭示了早期软件保护的策略和方法,...
AutoLISP是一种特定于AutoCAD的编程语言,它是基于LISP(列表处理)语言的简化版本,专为CAD用户设计,旨在简化和自动化CAD操作。AutoLISP工具是CAD用户尤其是五金模具设计师的得力助手,能够极大地提高工作效率和...
标题中的“Lisp-music-player.rar”表明这是一个基于Lisp语言开发的音乐播放器软件,其源代码或可执行文件被压缩在RAR格式的文件中。RAR是一种流行的压缩格式,通常用于存储和分发多个文件,它允许用户将多个文件...