原本以为这章很好理解,结果..杯具了。
在lisp中,变量分为两种:词汇变量(lexical),动态变量(dynamic)。#感觉很别扭,估计我翻坏了,虽然与其他语言做了类比,相当于:局部变量和全局变量。可是看了后面,似乎不是这么个回事啊。如果有资深lisper能够给出这两个变量的专业名称(中文),那真是不胜感激了。目前,好吧,就姑且从字面上来称呼这两种变量吧。
作为变量的基本要素之一就是,变量可以持有一个值。而在Lisp中,甚至无所谓值的类型。很爽,但也会有麻烦:只有到了编译的时候才会发现这方面的错误。
最常见的定义变量方式之一:
(defun foo (x y z) (+ x y z))
在定义函数时,不知不觉就定义了3个变量(x,y,z),这样的好处就是:不同的函数调用方互不影响。
另一种定义变量的方式:
(let (variable*)
body-form*)
(let ((x 10) (y 20) z)
...)
为了表现出变量的情况:
(defun foo (x)
(format t "Parameter: ~a~%" x) ; |<------ x is argument
(let ((x 2)) ; |
(format t "Outer LET: ~a~%" x) ; | |<---- x is 2
(let ((x 3)) ; | |
(format t "Inner LET: ~a~%" x)) ; | | |<-- x is 3
(format t "Outer LET: ~a~%" x)) ; | |
(format t "Parameter: ~a~%" x)) ; |
这里有用到LET,他还有一个变种:LET*,简单理解,就是let不允许用前面定义的变量,而let*则可以,例:
(let* ((x 10)
(y (+ x 10)))
(list x y)) ;这是可以的
(let ((x 10)
(y (+ x 10)))
(list x y)) ;这是不行的
(let ((x 10))
(let ((y (+ x 10)))
(list x y))) ;这样也是可以的,与第一种等价
词汇变量及闭包(好别扭的名字)
这里一段比较晦涩的描述,简单代码表示为:
(let ((count 0)) #'(lambda () (setf count (1+ count))))
这里面的count变量只能在随后的匿名函数中使用,过期不候,所以"局部又闭包"啊。
当然,万事有例外,要是函数在关闭时,定义、操作了个全局变量,那么就又不一样了:
(defparameter *fn* (let ((count 0)) #'(lambda () (setf count (1+ count)))))
试试:
(funcall *fn*)
1
(funcall *fn*)
2
(funcall *fn*)
3
动态变量
lisp的动态变量有两种声明方式:
(defvar *count* 0
"Count of widgets made so far.")
(defparameter *gap-tolerance* 0.001
"Tolerance to be allowed in widget gaps.")
两者间的差别是:defparameter必须带变量值,而defvar则无所谓。
虽说全局变量到处都能改,不过规范成一个函数,到处调用还是相当靠谱的:
(defun increment-widget-count () (incf *count*))
还有,虽然全局变量很好用,不过最好还是必须时用,天知道你的代码啥时候变量冲突了捏,一步小心影响了全局可就够喝一壶了。
下面有一段代码,类似于"局部屏蔽全局":
(defvar *x* 10)
(defun foo () (format t "X: ~d~%" *x*))
(foo)
X: 10
NIL
(let ((*x* 20)) (foo))
X: 20
NIL
(foo)
X: 10
NIL
(defun bar ()
(foo)
(let ((*x* 20)) (foo))
(foo))
(bar)
X: 10
X: 20
X: 10
NIL
想要操作全局变量的话:
(defun foo ()
(format t "Before assignment~18tX: ~d~%" *x*)
(setf *x* (+ 1 *x*))
(format t "After assignment~18tX: ~d~%" *x*))
(foo)
Before assignment X: 10
After assignment X: 11
NIL
(bar)
Before assignment X: 11
After assignment X: 12
Before assignment X: 20
After assignment X: 21
Before assignment X: 12
After assignment X: 13
NIL
如果这段代码理解不了,那么停住,理解了再继续。
全局变量的*号是约定成俗的,理论上来说,这样基本上就可以避免局部变量与整体变量间人为失误导致的冲突。
常量
定义方式:
(defconstant name initial-value-form [ documentation-string ])
常量算是一种特殊变量,绑定值后就不再变化。命名约定规则与动态变量相似,用加号(+)包夹。
分配
对于变量而言,赋值是通过宏setf进行的:
(setf place value)
还能一次赋值多个变量:
(setf x 1 y 2)
setf返回值为变量值,所以也可以多变量指同一个值:
(setf x (setf y (random 10)))
Lisp与其他语言赋值对应表:
Assigning to ... Java, C, C++ Perl Python
... variable x = 10; $x = 10; x = 10
... array element a[0] = 10; $a[0] = 10; a[0] = 10
... hash table entry -- $hash{'key'} = 10; hash['key'] = 10
... field in object o.field = 10; $o->{'field'} = 10; o.field = 10
Simple variable: (setf x 10)
Array: (setf (aref a 0) 10)
Hash table: (setf (gethash 'key hash) 10)
Slot named 'field': (setf (field o) 10)
其他的一些修改变量值的方式:
如果需要对变量进行一些针对原值的操作的话,比如:
(setf x (+ x 1))
着实麻烦了些,所以Lisp有内置的一些宏:
(incf x) === (setf x (+ x 1))
(decf x) === (setf x (- x 1))
(incf x 10) === (setf x (+ x 10))
还有ROTATEF和SHIFTF两种常用的宏:
(rotatef a b)
调换a b的值,
(shiftf a b 10)
将值左移:b的值给a,10赋给b。
这一章还有很多晦涩的描述(个人能力有限啊),不过,大体上lisp的变量就是如此了。结尾段给了好多的宏,呵呵,下一章将进入lisp之所以为lisp的世界:宏!
(未完待续)
分享到:
相关推荐
Common Lisp支持动态类型,这意味着变量可以在运行时绑定任何类型的值。此外,Common Lisp内置了垃圾回收机制,可以自动管理内存,减轻了程序员的负担。 #### 2. 宏系统 宏是Common Lisp的一大特色,它允许程序员...
common-lisp-the-language-second-edition.PDF
《Practical Common Lisp-1st-2005》是一本专注于Common Lisp编程语言的实用书籍,作者Peter Seibel通过这本书向读者展示了如何使用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语言中,符号(Symbols)是命名实体和变量的基础。它们在程序中用于标识数据和函数。列表(Lists)和cons是Lisp中的基本数据结构。列表是由cons对构成的链表,而cons是构成这些列表的基本单元。数组...
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 ...
这本《Practical Common Lisp》之所以号称Practical,正是因为这本书大量介绍Common Lisp在现实世界中的各种应用方式,算是第一本「入世传教」的Common Lisp著作。《Practical Common Lisp》是目前最畅销的Common ...
AutoLisp源文件--标注高程.LSP
在压缩文件中,只有一个名为"practical_common_lisp.pdf"的文件,这是本书的PDF版本。由于原版PDF文件较大,经过7z压缩后,文件大小显著减小,便于下载和存储,但同时也能保持较好的图像和文字质量,满足读者的阅读...
Common-Lisp.apk
计算多个数字之和、计算多条线段长度之和、插入墙高标注、查询多段线顶点坐标并绘制、自动生成页码、绘制示坡线、插入排水箭头 https://blog.csdn.net/qq_24141055/article/details/121446354
cad-lisp-3-表操作.LSP.lsp
ANSI Common Lisp 中文翻译版.pdf 此资源是 ANSI Common Lisp 的中文翻译版,涵盖了 Common Lisp 语言的基础知识和高级主题。该资源包含了 17 章节,从基础的列表、特殊数据结构、控制流程、函数、输入与输出、符号...
标题中的“Lisp-music-player.rar”表明这是一个基于Lisp语言开发的音乐播放器软件,其源代码或可执行文件被压缩在RAR格式的文件中。RAR是一种流行的压缩格式,通常用于存储和分发多个文件,它允许用户将多个文件...
### 实用Common Lisp编程知识点概览 #### 一、书籍简介与评价 《实用Common Lisp》是一本面向实际程序员的Lisp语言入门书籍。作者Peter Seibel通过一系列真实世界的问题来展示Common Lisp的强大之处,强调工程性和...
《AutoLISP工具在CAD中的应用详解》 AutoLISP是一种特定于AutoCAD的编程语言,它是基于LISP(列表处理)语言的简化版本,专为CAD用户设计,旨在简化和自动化CAD操作。AutoLISP工具是CAD用户尤其是五金模具设计师的...
Practical Common Lisp 学习lisp的入门书籍