变量
动态变量
defvar defparameter
(dafvar *paraname* default-value
"Documentation"
defparameter始终赋值
defvar只初始化,且可以不赋值
动态变量和词法变量的不同
使用let形式操作动态变量会产生和词法变量不一样的效果
词法变量在声明函数时确定了作用域。即说的时候是几就是几,被调用时还是声明时那个作用域的值。
动态变量在调用函数时寻找调用语境的作用域。即用的时候看环境,包含动态变量的函数调用的作用域的值决定函数内这个变量的值。
(let ((y 2))
(flet ((foo () y))
(let ((y 3))
(print (foo)))
(print (foo))))
------------------
2
2
(defvar *y* 1)
(let ((*y* 2))
(flet ((foo () *y*))
(let ((*y* 3))
(print (foo)))
(print (foo))))
------------------
3
2
本质是foo函数中动态变量/特殊变量是像当前作用域寻找*y*这个值,而词法变量是向声明函数时y的作用域寻找该值。
窃以为如果foo是个宏,词法变量和动态变量会获得一样的效果。回头学了宏来试一试。
脑内解释
词法变量:因为值跟上下文的文本关系更强,与调用的环境无关。
动态变量:同样的函数在不同作用域下可能变现出不同值,叫动态变量合情合理。不适合称为全局变量。
常量
defconstant
+variablename+
常量命名,不能被用于形参和重绑定
赋值
setf place value
setf place1 value1 place2 value2
返回最后赋予的值
(setf x (set y 10))
= 把复制给y的结果赋给x
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)
修改宏
(incf x) = (setf x (+ x 1))
(incf x 10) = (setf x (+ x 10)
修改宏一般可以保证从左到右执行,保证参数和位置形式的子形式只被执行一次。
shiftf rotatef
(shiftf a b c)
值向左传递,返回最左
(rotatef a b c)
值向左传递,最右变量获得最左的值,返回nil
宏
展开期(macro expansion time)
运行期(runtime)
(defmacro name (parameter*)
"Optional documentation string."
body-form*)
do
(do (variable-definition*)
(end-test-form result-form*)
statement*)
variable-definition
(var init-form step-form)
数字、字符、字符串、符号引用
#\a
字符a
#\Space
空格
'bar ->BAR
单引号加字符串,如’bar,表示这个字符串的符号(symbol)对象。
集合
向量
#(a b c)
#号打头的列表
集合操作
find
count
subsitute
position
remove
关键字
:test 类似于上述函数的-if版本,如count-if。
(count #\a #(a b c d e))
>1
(count #\a #(1 2 3 4 5) :test $'evenp)
> 2
(count-if #'evenp #(1 2 3 4 5))
> 2
:key 对集合元素做一定提取,比如元素也是合集,可以用它提取选择提取哪个。
(count #\a #((a 10) (b 20) (c 30)) :key #'first)
其中处理(a 10)时,就会提取第一个元素a和#\a进行对比。
:start
:end Num|Nil
若指定Nil,则到末尾
:from-end T
从后往前
:count
在remove和substitute中,表示生效几次
合并
concatenate
(concatenate 'vector #(1 2 3) '(4 5 6)) -> #(1 2 3 4 5 6)
(concatenate 'list #(1 2 3) '(4 5 6)) -> (1 2 3 4 5 6)
(concatenate 'string "abc" '(#\d #\e #\f)) -> "abcdef"
merge (含排序)
(merge 'vector #(1 3 5) #(2 4 6) #'<) -> #(1 2 3 4 5 6)
(merge 'list #(1 3 5) #(2 4 6) #'<) -> (1 2 3 4 5 6)
排序
sort
和sort-stable
破坏性:改变参数
(setf my-sequence (sort my-sequence #'string<))
(sort my-sequence #'string<)
:key
关键字,提取的关键字只用于排序算法,而不是排序内容
子序列
(defparameter *x* (copy-seq "foobarbaz"))
(setf (subseq *x* 3 6) "xxx")
*x* -> "fooxxxbaz"
(setf (subseq *x* 3 6) "abcd")
*x* -> "fooabcbaz"
(setf (subseq *x* 3 6) "xx")
*x* -> "fooxxcbaz"
mismatch
(mismatch "foobarbaz" "foom") -> 3
(mismatch "foobar" "bar" :from-end t) -> 3
序列谓词
(every #'evenp #(1 2 3 4 5)) -> NIL
(some #'evenp #(1 2 3 4 5)) -> T
(notany #'evenp #(1 2 3 4 5)) -> NIL
(notevery #'evenp #(1 2 3 4 5)) -> T
(every #'> #(1 2 3 4) #(5 4 3 2)) -> NIL
(some #'> #(1 2 3 4) #(5 4 3 2)) -> T
(notany #'> #(1 2 3 4) #(5 4 3 2)) -> NIL
(notevery #'> #(1 2 3 4) #(5 4 3 2)) -> T
映射
map
跟mathamatica的map一样的用法,给定一个谓词把n个序列的元素进行运算,返回一个新序列
*需要指定类型 'list
or 'vecotr
(map 'vector #'* #(1 2 3 4 5) #(10 9 8 7 6)) -> #(10 18 24 28 30)
map-into
把返回结果放进第一个参数里(一个序列)
如果长度不统一以最短的为准
(map-into a #'+ a b c)
reduce
:initial-value 逻辑上提供一个第一位
(reduce #'+ #(1 2 3 4 5 6 7 8 9 10)) -> 55
哈希表
make-hash-table
创建哈希表
hash的等价判断可以通过:test关键字传递,但仅接受EQUAL
EQ
和 EQUALP
(defparameter *h* (make-hash-table))
(gethash 'foo *h*) -> NIL
(setf (gethash 'foo *h*) 'quux)
(gethash 'foo *h*) -> QUUX
GETHASH
隐式地返回两个值,“值”和“是否存在”。与形参形式中(c Nil c-p)
/(形参名 默认值 是否赋值)
很像,用于判断是传值为Nil
还是因为没有值才Nil
。
*多重返回值的工作方式决定,如果没有显示处理,额外返回值会被丢弃。即视为一个返回值。
(defun show-value (key hash-table)
(multiple-value-bind (value present) (gethash key hash-table)
(if present
(format nil "Value ~a actually present." value)
(format nil "Value ~a because key not found." value))))
(setf (gethash 'bar *h*) nil)
(show-value 'foo *h*) -> "Value QUUX actually present."
(show-value 'bar *h*) -> "Value NIL actually present."
(show-value 'baz *h*) -> "Value NIL because key not found."
迭代
maphash
两个参数
(maphash #'(lambda (k v) (format t "~a => ~a~%" k v)) *h*)
remhash 按key删除一个表格内容
(maphash #'(lambda (k v) (when (< v 10) (remhash k *h*))) *h*)
点对单元
(CAR . CDR)
(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)
列表
多数列表函数使用函数式编写,这么做是有好处的,因为他们可以在返回结果中直接使用一部分实参。
比如append这样的函数用于链接2个列表,基于点对单元特征,可以把任意新列表的CDR连接到后者。
破坏性
基于上文提到的修改点对单元的操作,可能产生破坏参数的特征。只有当确认参数不在使用时,调用破坏性函数才是安全的。
(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)
*list-3* -> (1 2 0 4)
破坏性 & 回收性
回收性函数
NREVERSE
Non-consing,不分配新的点对单元。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)