在Common Lisp中引用函数似乎有许多不同的方法:
通过符号,其中符号出现(未引用)作为形式的汽车(1+ 2) => 3,或在功能参数位置(mapcar '1+ '(1 2 3)) => (2 3 4);
通过功能对象,其中,所述(解释或编译)函数对象可以出现在函数自变量的位置中(mapcar #'1+ '(1 2 3)) => (2 3 4)或(mapcar (symbol-function '1+) '(1 2 3)) => (2 3 4),而不是作为一种形式如在车上(#'1+ 2) => error或((symbol-function '1+) 2) => error;
通过lambda表达式,其中lambda表达式显示为lambda形式的汽车((lambda (x) (1+ x)) 2) => 3,或者在函数参数位置中显示(mapcar (lambda (x) (1+ x)) '(1 2 3)) => (2 3 4)[但是,Hyperspec不会将lambda表达式识别为"函数指示符"].
在这三种"方式"中,对我而言,第一种似乎有些不合适,因为它似乎使Common Lisp运算符仅仅评估其参数一次的基本准则复杂化.如果在上面的示例'1+中进行评估,它将生成符号1+ …
在实用Common Lisp的第8章末,Peter Seibel展示了once-only宏观.其目的是通过用户定义的宏中的变量评估来缓解一些微妙的问题.注意我在这一点上并没有试图理解这个宏如何工作,就像在其他一些帖子中一样,但是如何正确使用它:
(defmacro once-only ((&rest names) &body body)
(let ((gensyms (loop for n in names collect (gensym))))
`(let (,@(loop for g in gensyms collect `(,g (gensym))))
`(let (,,@(loop for g in gensyms for n in names collect ``(,,g ,,n)))
,(let (,@(loop for n in names for g in gensyms collect `(,n ,g)))
,@body)))))
Run Code Online (Sandbox Code Playgroud)
以下是一个示例(不正确)设计宏,试图展示几个变量评估问题.它声称通过某个delta迭代一系列整数,返回范围:
(defmacro do-range ((var start stop delta) &body body)
"Sample macro with faulty variable evaluations."
`(do ((,var ,start (+ ,var ,delta))
(limit …Run Code Online (Sandbox Code Playgroud) 以下是旨在用作(lifo)堆栈或(fifo)队列的结构
(defstruct jvector
(vector (make-array 0 :adjustable t :fill-pointer 0) :type (array * (*)))
(start 0 :type (integer 0 *)))
Run Code Online (Sandbox Code Playgroud)
内容的范围从jvector-start到jvector-vector填充指针。我希望能够用类似的东西指定内容的元素类型
(defun create-jvector (&key (element-type t))
(make-jvector :vector (make-array 0 :element-type element-type :adjustable t :fill-pointer 0)
:start 0))
Run Code Online (Sandbox Code Playgroud)
并用
(defun push-jvector (elt jvec)
(vector-push-extend elt (jvector-vector jvec)))
Run Code Online (Sandbox Code Playgroud)
但是,create-jvector中的元素类型将被忽略。例如,
* (defparameter v (create-jvector :element-type 'integer))
V
* v
#S(JVECTOR :VECTOR #() :START 0)
* (push-jvector 1 v)
0 ;OK result
* v
#S(JVECTOR :VECTOR #(1) :START 0)
* (push-jvector 'a v) …Run Code Online (Sandbox Code Playgroud) 他说,在Paul Graham的书" ANSI Common Lisp"中,他讨论了符号与字符串操作
符号可以一步比较
eql......"
(P138).以下是符号比较的两种情况:
(setq x 3)
3
(setq a 'x)
X
(setq b 'x)
X
(eq a b)
T
Run Code Online (Sandbox Code Playgroud)
因此,由于a和b指向相同的符号对象,名为X,因此它们是eq.然而,这与之形成鲜明对比
(setq a (copy-symbol 'x))
#:X
(setq b (copy-symbol 'x))
#:X
(symbol-name a)
"X"
(symbol-name b)
"X"
(eq a b)
NIL
(eql a b)
NIL
(equal a b)
NIL
(equalp a b)
NIL
Run Code Online (Sandbox Code Playgroud)
现在,a和b指向不同的符号对象,即使它们具有相同的符号名称和相同的打印名称.我的问题是:
eql而不是eq,而且equalp?Common Lisp似乎竭尽全力提供非破坏性功能(如subst和remove)和破坏性功能以及修改宏(如delete和rotatef)以供一般使用.据推测,这是为了有效地支持功能和非功能的编程风格.但是在无处不在的设计中似乎也存在对非功能性风格的特殊偏见setf.setf包含通用引用的宏显然足够灵活,可以修改任何可指定的位置(除了可能的不可变整数和字符).尽管其无功能/破坏性行为,但这种力量可能是其广泛使用的原因.
问题是为什么没有相应的"功能样式"非破坏性操作符,后面的图案setf(称之为put,因为set已经采用),类似于其他非破坏性/破坏性的lisp操作符对.这样的运算符可能会使用相同的参数,一个位置和一个值,但会返回嵌入了该位置的对象的副本,而不是该位置的新值.它也可能涉及某种通用复印机,标准setf只是在返回之前修改副本.然后可以使用非破坏性运算符代替setf大多数分配,并setf为大型对象保留.鉴于通用复印机的(推测)要求以及从嵌入其中的任意位置恢复物体的需要,这样的操作者是否可行(甚至可能)?
当可以从多个线程访问/更新变量时,通常需要保护它免受同时更改的影响。一种有效的方法是使用原子函数来保证互斥访问。例如(sb-ext:atomic-incf *count*)。另一种方法是像这样围绕更新操作包装一个锁(bt:with-lock-held (*lock*) (incf *count*)),但这有点昂贵。
有没有一种有效的方法可以在多线程代码中包含库函数(例如来自亚历山大图书馆)?例如,如果 (alexandria:deletef x *list*)要从多个线程中执行操作?还是需要锁?(ps:我假设a deletef需要保护,但不能完全确定。)
Common Lisp宏pushnew返回作为参数给出的(可能已更新)位置列表。看来,如果您想知道给定的项目是否实际被推送,则需要比较放置前和放置后列表以查看其是否已更改。但这对于我的使用来说效率太低,因为它将涉及重复比较两个复杂结构对象的列表以得出等效结果。
另一种可行的替代方法是使用:test参数来pushnew记录是否已找到该项目,因为已扫描列表元素。如果找到该项目,则可以将T作为第二个整数值返回,否则返回NIL。下面的宏尝试执行此操作:
(defmacro pushnew+p (item place &key test (key #'identity) &aux old?)
"Same as pushnew, but also returns whether item was pushed."
`(values (pushnew ,item ,place
:test (lambda (item element)
(if ,test
(setf old? (funcall ,test item element))
(setf old? (eql item element))))
:key ,key)
(not old?)))
Run Code Online (Sandbox Code Playgroud)
似乎工作正常,因为
(defparameter x '(1 2 3))
(pushnew+p 0 x) -> (0 1 2 3), T
(pushnew+p 2 x) -> (0 1 2 3), NIL
(defparameter y '((1) (2) …Run Code Online (Sandbox Code Playgroud) 我需要一些帮助来理解编译 lambda 表达式时出现的 SBCL 编译器警告消息。lambda 表达式临时存储为用户定义名称的符号值,编译后的函数随后存储在名称的符号函数下。
* (compile nil (symbol-value 'activate-connector-if!))
; in: LAMBDA (STATE ?CONNECTOR)
; (APPLY #'SOME
; (LAMBDA (WOULDWORK-PKG::?T1 WOULDWORK-PKG::?T2)
; (AND
; (GETHASH (+ 126 # #)
; (WOULDWORK-PKG::PROBLEM-STATE.IDB WOULDWORK-PKG::STATE))
; (GETHASH (+ 126 # #)
; (WOULDWORK-PKG::PROBLEM-STATE.IDB WOULDWORK-PKG::STATE))
; (LET (#)
; (WHEN VALUES #))
; (LET (#)
; (WHEN VALUES #))
; (NOT (EQL WOULDWORK-PKG::$HUE1 WOULDWORK-PKG::$HUE2))))
; NIL NIL)
; --> MULTIPLE-VALUE-CALL SB-C::%FUNCALL SOME LET BLOCK SB-INT:DX-FLET FLET
; --> #:WRAPPER102 BLOCK LET
; …Run Code Online (Sandbox Code Playgroud) 最初将大量符号存储在一个包中(与项目包分开),并有效地将其用作项目可访问的哈希表(其中键表示简单的集合成员资格数据)是否可行?
* (defpackage :project (:use :cl))
#<PACKAGE "PROJECT">
* (defpackage :temp (:use :cl))
#<PACKAGE "TEMP">
* (in-package :project)
#<PACKAGE "PROJECT">
* (intern "ABC" :temp)
TEMP::ABC
NIL
* (find-symbol "ABC" :temp)
TEMP::ABC
:INTERNAL
;The following is not needed for this project, but is available
* (setf (symbol-value (find-symbol "ABC" :temp)) 123)
123
* (symbol-value (find-symbol "ABC" :temp))
123
Run Code Online (Sandbox Code Playgroud)
这似乎可行,但是有充分的理由避免并仅使用哈希表来代替吗?我的第一个想法是避免使用大量杂项键符号使项目包变得混乱。这些符号将在运行时从字符串生成(以检查哈希表中的集合成员资格)。这似乎涉及许多符号的运行时驻留,这些符号可能存储在表中,也可能不存储在表中。但我也想知道是否find-symbol可以比gethash. 或者,我可以只使用equal字符串的哈希表,但查找的绝对数量似乎指向eq而不是equal。寻找任何明智的建议,谢谢。
编辑:将equal哈希表与包符号查找进行比较的简单测试。
一、哈希表测试
* (defun random-string (n)
"Generate a random …Run Code Online (Sandbox Code Playgroud) 我正在尝试将一个常见的 Lisp 结构以可读的方式打印到一个文件中,以便稍后可以将其读回。SBCL 似乎有一些相当复杂的内置工具,用于以可读方式打印复杂对象,这可以避免编写专门的打印对象方法。
我的结构是否有可能:print-function干扰*print-readably*?
(defstruct (problem-state (:conc-name problem-state.) (:print-function print-problem-state) (:copier nil))
"A planning state including the current propositional database."
(name nil :type symbol) ;last action executed
(instantiations nil :type list) ;from last action effect
(happenings nil :type list) ;a list of (object (next-index next-time next-direction)) pairs
(time 0.0 :type real)
(value 0.0 :type real)
(heuristic 0.0 :type real)
(idb (make-hash-table) :type hash-table) ;integer hash table of propositions
(hidb (make-hash-table) :type hash-table)) ;integer table for …Run Code Online (Sandbox Code Playgroud)