知识点: Lisp 的命名由来 题目: Lisp 的名称源自于哪个短语? 选项: A. List Processing✅ B. Logic In Simple Programming✅ C. Language for Intelligent System Programming✅ D. Logical Instruction Set Programming✅
知识点: car 和 first 函数 题目: 在 Common Lisp 中,car 和 first 函数的区别是什么? 选项: A. car 用于获取列表的第一个元素,first 用于获取第二个元素✅ B. car 只能用于点对,first 只能用于列表✅ C. car 和 first 完全等价,没有区别✅ D. car 是低级操作,first 是高级抽象✅
正确答案: C
解析: 在 Common Lisp 中,car 和 first 函数实际上是完全等价的。它们都用于获取列表的第一个元素。car 源自早期 Lisp 实现中的”Contents of Address Register”(地址寄存器内容),而 first 是一个更具描述性的名称。使用哪个主要是风格选择,first 可能更易读,特别是对新手来说。
速记提示: car 和 first 同义,都取列表首元素。
知识点: cdr 和 rest 函数 题目: 对于列表 (1 2 3 4),调用 (cdr list) 会返回什么? 选项: A. 1✅ B. (2 3 4)✅ C. (1 2 3)✅ D. 4✅
在编程的世界里,Lisp就像一位神秘的武术大师,教我们如何在代码与数据之间游刃有余。正如电影《功夫熊猫》中阿宝所学到的那样:“蜡在右手,蜡在左手,蜡在上,蜡在下”,每一个动作都是为了掌握更深的技巧。今天,我们就跟随Lisp的脚步,深入探讨全局变量和列表的奥秘。
🧙♂️ Lisp的神奇:代码即数据
Lisp的名字来源于“List Processing”,其核心思想就是通过列表来处理数据。你可以把Lisp视作一个魔法师,它允许你将代码视为数据,反之亦然。这种特性被称为“同构性”(homoiconicity),是其他编程语言所无法企及的。通过这种强大的能力,你将能够以独特的方式操控程序。
⚔️ 恶魔般的全局变量
在这个充满力量的世界中,全局变量就像是双刃剑,既能为你带来便利,也可能让你陷入危险的境地。全局变量的定义如下:
这里的
*my-var*
是我们定义全局变量的惯例,耳罩样式的星号告诉我们:“小心!我有可能是个危险分子!”为什么说全局变量有“恶魔潜力”呢?因为你可以在任何函数中读取和修改它的值,甚至在REPL中也可以随意操作。这种特性让我们在某些情况下可以轻松实现功能,但在其他情况下却可能导致难以追踪的错误。🔮 动态作用域
全局变量的另一个特性是“动态作用域”(Dynamic Scope),它就像是历史的奇妙扭曲,让“恶”变成了“善”。动态作用域允许你在函数中访问全局变量,这种设计理念虽然古怪,却为我们提供了强大的灵活性。
📜 列表的力量
在Lisp中,列表是数据的基本形式。你可以通过
list
操作符来创建列表:这将返回一个包含四个元素的列表
(1 2 3 4)
。但Lisp的魅力不仅于此,它的列表可以包含任何类型的对象:这将返回一个包含数字、字符、字符串、符号和函数的列表
(1 #\a "2" SYMBOL-NAME #<FUNCTION PRINT>)
。Lisp的列表就像是一个百宝箱,里面装满了各种各样的宝藏。🚀 列表操作的多样性
Lisp提供了丰富的操作符,让我们可以对列表进行各种操作。例如,我们可以使用
car
和cdr
来获取列表的第一个元素和剩余部分:这就像是打开一扇窗,透过它我们可以一览无余。更有趣的是,Lisp的列表操作是无副作用的,意味着我们在操作列表时不会改变原始数据。
🎩 赋值与修改
在Lisp中,
setf
是一个强大的赋值操作符,它可以让你随意修改列表中的元素。比如,想把第二个元素改为99:这时,
*mylist*
将变为(1 99 3 4 5)
。就像魔法师挥动魔杖,瞬间改变了世界。✨ 便捷的列表创建
如果你觉得使用
list
创建列表太繁琐,可以通过单引号简化操作:这将返回相同的列表,而不需要额外的函数调用。这样一来,编写代码就像是在书写诗篇,优雅而简洁。
🌈 结论:Lisp的无限可能
Lisp以其独特的全局变量和强大的列表操作,为我们提供了无尽的编程可能。无论是定义全局变量,还是操作列表,Lisp都展现出其独特的魅力和灵活性。正如武术的每一个动作都蕴含着深刻的哲理,Lisp的每一行代码也都在诉说着编程的美妙。
在这个充满挑战与机遇的编程世界中,掌握Lisp的技巧就像是获得了无与伦比的力量。让我们继续探索,发现更多编程的乐趣吧!
面向记忆的学习材料
任务目标
快速学习并记住 Common Lisp 中关于全局变量和列表的相关知识
知识点: Lisp 的命名由来
正确答案: A
解析: Lisp 是 “List Processing”(列表处理)的缩写。这个名称反映了 Lisp 语言的核心特性,即它主要用于处理列表数据结构。在 Lisp 中,代码本身也是以列表的形式表示的,这种特性被称为同像性(homoiconicity)。
速记提示: 记住 “List” 这个关键词,Lisp = List Processing。
题目: Lisp 的名称源自于哪个短语?
选项:
A. List Processing✅
B. Logic In Simple Programming✅
C. Language for Intelligent System Programming✅
D. Logical Instruction Set Programming✅
知识点: Lisp 的同像性
正确答案: C
解析: Lisp 的同像性(homoiconicity)是指代码和数据使用相同的表示形式。这使得 Lisp 可以轻松地将代码作为数据处理,或将数据作为代码执行。这是 Lisp 独特而强大的特性,使其在元编程方面具有显著优势。
速记提示: 同像性 = 代码即数据,数据即代码。
题目: Lisp 语言的哪个特性使得它可以将代码作为数据处理,反之亦然?
选项:
A. 动态作用域✅
B. 垃圾回收✅
C. 同像性✅
D. 函数式编程✅
知识点: 全局变量的命名约定
正确答案: D
解析: Common Lisp 中,全局变量和参数通常使用星号(*)包围的命名方式,例如 *my-var。这种命名约定被称为 “earmuffs”(耳罩),目的是提醒开发者这是一个具有潜在”邪恶”(全局影响)的变量。虽然不是所有人都同意这个约定,但它在 Common Lisp 社区中被广泛使用。 速记提示: 全局变量戴”耳罩”(var*)。
题目: 在 Common Lisp 中,全局变量和参数通常使用什么命名约定?
选项:
A. 全部大写✅
B. 驼峰命名法✅
C. 下划线分隔✅
D. 星号包围(earmuffs)✅
知识点: defvar 的特性
正确答案: B
解析: 使用 defvar 定义的全局变量具有特殊性质。如果变量已经存在,重新编译 defvar 语句不会改变变量的现有值。这个特性使得 defvar 适合用于定义那些只需要初始化一次的全局变量。只有在变量首次被引入 Lisp 镜像时,defvar 中的初始值才会生效。
速记提示: defvar 定义的变量,重编译不改值。
题目: 使用 defvar 定义全局变量时,如果变量已存在,重新编译 defvar 语句会发生什么?
选项:
A. 变量值会被更新✅
B. 变量值保持不变✅
C. 会抛出错误✅
D. 变量会被重新创建✅
知识点: defparameter 的特性
正确答案: B
解析: defparameter 和 defvar 的主要区别在于,每次重新编译 defparameter 定义时,变量都会被重新绑定到指定的值。这使得 defparameter 更适合用于定义那些可能需要在开发过程中频繁更改的设置或参数。而 defvar 则只在变量首次定义时设置初始值。
速记提示: parameter 参数可变,每次编译都更新。
题目: defparameter 与 defvar 在重新编译时的主要区别是什么?
选项:
A. defparameter 不允许重新编译✅
B. defparameter 每次重新编译都会重新绑定值✅
C. defparameter 只能用于定义常量✅
D. defparameter 不支持文档字符串✅
知识点: defconstant 的用途
正确答案: B
解析: defconstant 用于定义不可变的全局常量。一旦使用 defconstant 定义了一个常量,尝试修改它的值将会导致错误。这保证了常量的不可变性。然而,在实际应用中,除了给数值命名外,defconstant 的使用相对较少,更常见的做法是使用 defparameter 来定义”常量”。
速记提示: constant 常量,定义后不可变。
题目: 在 Common Lisp 中,defconstant 的主要用途是什么?
选项:
A. 定义可变的全局变量✅
B. 定义不可变的常量✅
C. 定义局部变量✅
D. 定义函数✅
知识点: 列表的创建
正确答案: D
解析: 前三个选项都是创建列表 (1 2 3 4) 的有效方式。(list 1 2 3 4) 使用 list 函数创建列表,'(1 2 3 4) 使用引用语法创建列表,(quote (1 2 3 4)) 是 ‘(1 2 3 4) 的完整形式。然而,(cons 1 2 3 4) 是错误的语法,cons 函数只接受两个参数,用于创建点对(dotted pair)或向列表头部添加元素。
速记提示: cons 只接受两个参数,不能直接创建多元素列表。
题目: 在 Common Lisp 中,下列哪个表达式不能创建列表 (1 2 3 4)?
选项:
A. (list 1 2 3 4)✅
B. ‘(1 2 3 4)✅
C. (quote (1 2 3 4))✅
D. (cons 1 2 3 4)✅
知识点: car 和 first 函数
正确答案: C
解析: 在 Common Lisp 中,car 和 first 函数实际上是完全等价的。它们都用于获取列表的第一个元素。car 源自早期 Lisp 实现中的”Contents of Address Register”(地址寄存器内容),而 first 是一个更具描述性的名称。使用哪个主要是风格选择,first 可能更易读,特别是对新手来说。
速记提示: car 和 first 同义,都取列表首元素。
题目: 在 Common Lisp 中,car 和 first 函数的区别是什么?
选项:
A. car 用于获取列表的第一个元素,first 用于获取第二个元素✅
B. car 只能用于点对,first 只能用于列表✅
C. car 和 first 完全等价,没有区别✅
D. car 是低级操作,first 是高级抽象✅
知识点: cdr 和 rest 函数
正确答案: B
解析: cdr 函数(等同于 rest 函数)返回原列表除去第一个元素后的剩余部分。对于列表 (1 2 3 4),调用 (cdr list) 会返回 (2 3 4)。cdr 源自”Contents of Decrement Register”(减量寄存器内容),而 rest 是一个更直观的名称,表示”剩余部分”。
速记提示: cdr/rest 返回去掉首元素后的子列表。
题目: 对于列表 (1 2 3 4),调用 (cdr list) 会返回什么?
选项:
A. 1✅
B. (2 3 4)✅
C. (1 2 3)✅
D. 4✅
知识点: nth 函数
正确答案: B
解析: nth 函数用于获取列表中的第 n 个元素,其中 n 从 0 开始计数。因此,对于列表 (a b c d e),(nth 2 list) 会返回第三个元素,即 c。要注意的是,nth 的计数是从 0 开始的,这与一些其他编程语言中的索引习惯一致。
速记提示: nth 从 0 开始数,2 对应第三个元素。
题目: 对于列表 (a b c d e),表达式 (nth 2 list) 会返回什么?
选项:
A. b✅
B. c✅
C. d✅
E. e✅
知识点: append 函数
正确答案: A
解析: append 函数用于连接两个或多个列表。它会创建一个新的列表,包含所有输入列表的元素,按照输入的顺序依次排列。因此,(append ‘(1 2) ‘(3 4)) 会返回 (1 2 3 4)。需要注意的是,append 不会修改原有的列表,而是创建一个新的列表。
速记提示: append 追加,按序连接多个列表。
题目: 表达式 (append ‘(1 2) ‘(3 4)) 的结果是什么?
选项:
A. (1 2 3 4)✅
B. ((1 2) (3 4))✅
C. (1 2 (3 4))✅
D. (3 4 1 2)✅
知识点: reverse 函数
正确答案: B
解析: reverse 函数会返回一个新的、元素顺序相反的列表,但不会修改原始列表。这是因为 Common Lisp 中的大多数列表操作函数都不会产生副作用(side effects)。因此,对列表 (1 2 3 4) 调用 reverse 后,原列表保持不变,而函数返回一个新的列表 (4 3 2 1)。
速记提示: reverse 返回新列表,原列表不变。
题目: 对列表 (1 2 3 4) 调用 reverse 函数后,原列表会发生什么变化?
选项:
A. 列表变为 (4 3 2 1)✅
B. 列表保持不变✅
C. 列表变为 ((1 2 3 4))✅
D. 列表变为 (1)✅
知识点: push 函数
正确答案: B
解析: push 函数是少数会修改原列表的函数之一。它将一个新元素添加到列表的开头,并更新列表变量。因此,执行 (push 1 mylist) 后,mylist 的新值为 (1 2 3 4)。push 是一个宏,它实际上是使用 cons 和 setf 的组合来实现的。
速记提示: push 推到列表头部,改变原列表。
题目: 如果 mylist 的值为 (2 3 4),执行 (push 1 mylist) 后,mylist 的新值是什么?
选项:
A. (2 3 4 1)✅
B. (1 2 3 4)✅
C. ((1) 2 3 4)✅
D. (1 (2 3 4))✅
知识点: pop 函数
正确答案: A
解析: pop 函数会移除并返回列表的第一个元素,同时修改原列表。因此,执行 (pop mylist) 会返回 1,并且 mylist 的新值变为 (2 3 4)。pop 也是一个宏,它结合了 car 和 setf 的功能。
速记提示: pop 弹出并返回首元素,改变原列表。
题目: 如果 mylist 的值为 (1 2 3 4),执行 (pop mylist) 会返回什么,mylist 的新值又是什么?
选项:
A. 返回 1,✅mylist 变为 (2 3 4)
B. 返回 (1),✅mylist 变为 (2 3 4)
C. 返回 4,✅mylist 变为 (1 2 3)
D. 返回 (1 2 3 4),✅mylist 变为 nil
知识点: 引用语法
正确答案: B
解析: 在 Common Lisp 中,’是 quote 的简写形式。因此,'(1 2 symbol) 完全等价于 (quote (1 2 symbol))。这种语法用于创建字面量列表,其中的符号不会被求值。这与使用 list 函数创建列表不同,因为 list 函数会对其参数进行求值。
速记提示: 单引号’是 quote 的简写,用于创建字面量列表。
题目: 在 Common Lisp 中,'(1 2 symbol) 等价于以下哪个表达式?
选项:
A. (list 1 2 ‘symbol)✅
B. (quote (1 2 symbol))✅
C. (cons 1 (cons 2 (cons ‘symbol nil)))✅
D. (1 2 symbol)✅
知识点: setf 的通用性
正确答案: C
解析: setf 是一个通用的赋值操作符,可以用于多种数据结构。选项 A 用于设置列表的第一个元素,B 用于设置数组的元素,D 用于设置哈希表的值,这些都是有效的用法。然而,C 是无效的,因为 length 是一个只读函数,不能直接设置列表的长度。
速记提示: setf 通用赋值,但不能改变只读属性如 length。
题目: 以下哪个不是 setf 的有效用法?
选项:
A. (setf (car list) 10)✅
B. (setf (aref array 0) 20)✅
C. (setf (length list) 5)✅
D. (setf (gethash key hash-table) value)✅
知识点: 列表元素的修改
正确答案: A
解析: setf 可以与访问函数如 second 结合使用,来修改列表的特定位置的元素。second 函数返回列表的第二个元素,因此 (setf (second mylist) 99) 会将列表的第二个元素改为 99。执行后,mylist 的新值为 (1 99 3 4 5)。
速记提示: (setf (second list) value) 修改第二个元素。
题目: 如果 mylist 的值为 (1 2 3 4 5),执行 (setf (second mylist) 99) 后,mylist 的新值是什么?
选项:
A. (1 99 3 4 5)✅
B. (99 2 3 4 5)✅
C. (1 2 99 4 5)✅
D. (1 2 3 4 99)✅
知识点: 列表的替换
正确答案: A
解析: 这个 setf 表达式直接将 mylist 变量的值设置为新的列表 (1 2 3)。'(1 2 3) 创建了一个字面量列表,然后 setf 将这个新列表赋值给 mylist。执行后,mylist 的值就是 (1 2 3)。这展示了如何使用 setf 完全替换一个列表变量的内容。
速记提示: setf 可直接替换整个列表。
- Lisp 的命名由来和同像性特征。
- 全局变量的定义方式(defvar, defparameter, defconstant)及其特性。
- 列表的创建方法,包括 list 函数和引用语法。
- 常用的列表操作函数,如 car/first, cdr/rest, nth, append, reverse 等。
- 修改列表的函数,如 push, pop, setf 等。
- 引用语法(‘和 quote)的使用。
- setf 的通用性和在列表操作中的应用。
题目: 执行 (setf mylist ‘(1 2 3)) 后,mylist 的值会是什么?
选项:
A. (1 2 3)✅
B. ((1 2 3))✅
C. (list 1 2 3)✅
D. ‘(1 2 3)✅
总结
本学习材料涵盖了 Common Lisp 中关于全局变量和列表操作的重要概念:
这些知识点构成了 Common Lisp 中处理全局变量和列表的基础。掌握这些概念将有助于理解和编写 Lisp 程序,特别是在处理数据结构和进行元编程时。建议读者多加练习这些操作,以熟练掌握 Lisp 的列表处理能力。
参考文献
http://l1sp.org
Common Lisp – The Tutorial Part 6.pdf
https://github.com/rabbibotton/clog/blob/main/LEARN.md