我是Common Lisp的初学者,遇到了这段代码:
(let ((foo (list 42)))
(setf (rest foo) foo))
Run Code Online (Sandbox Code Playgroud)
在尝试执行它时,REPL似乎永远循环.
Common Lisp似乎竭尽全力提供非破坏性功能(如subst和remove)和破坏性功能以及修改宏(如delete和rotatef)以供一般使用.据推测,这是为了有效地支持功能和非功能的编程风格.但是在无处不在的设计中似乎也存在对非功能性风格的特殊偏见setf.setf包含通用引用的宏显然足够灵活,可以修改任何可指定的位置(除了可能的不可变整数和字符).尽管其无功能/破坏性行为,但这种力量可能是其广泛使用的原因.
问题是为什么没有相应的"功能样式"非破坏性操作符,后面的图案setf(称之为put,因为set已经采用),类似于其他非破坏性/破坏性的lisp操作符对.这样的运算符可能会使用相同的参数,一个位置和一个值,但会返回嵌入了该位置的对象的副本,而不是该位置的新值.它也可能涉及某种通用复印机,标准setf只是在返回之前修改副本.然后可以使用非破坏性运算符代替setf大多数分配,并setf为大型对象保留.鉴于通用复印机的(推测)要求以及从嵌入其中的任意位置恢复物体的需要,这样的操作者是否可行(甚至可能)?
读这个问题让我思考什么构成了一个有效的表达式汽车.显然,可以使用通常的语法"调用"符号和lambdas.按照hyperspec,
函数名 ñ.1.(在环境中)符号或列表(setf符号),它是该环境中函数的名称.2.符号或列表(setf符号).
因此,理论上讲,它(setf some-name)是一个函数名称.我决定尝试一下.
(defun (setf try-this) ()
(format t "Don't name your functions like this, kids :)"))
((setf try-this))
(funcall '(setf try-this))
(setf (try-this))
Run Code Online (Sandbox Code Playgroud)
GNU CLISP,SBCL和ABCL都将让我定义这个功能.但是,SBCL和ABCL不允许我使用代码段中显示的任何语法来调用它.另一方面,CLISP将运行前两个但仍然在第三个错误.
我很好奇哪个编译器的行为正确.由于SBCL和ABCL同意,我猜测正确的实现应该拒绝该代码.作为第二个问题,我如何从代码片段中调用我令人难以置信的无用功能,因为我上面尝试过的东西不能轻松工作.或者,也许更有用,
是否可以非破坏性地将新的键值对添加到 Common Lisp (SBCL) 哈希表中?向哈希表添加新元素的标准方法是调用:
(setf (gethash key *hash-table*) value)
Run Code Online (Sandbox Code Playgroud)
但调用setf修改*hash-table*破坏了原件。我有一个应用程序,我想利用哈希表查找的效率,但我也想非破坏性地修改它们。我看到的解决方法是在对其进行操作之前复制原始哈希表,但这在我的情况下不切实际,因为我正在处理的哈希表包含数千个元素并复制大型哈希表,例如循环首先会否定使用它们的计算效率优势。
我正在尝试定义一个宏,它将获取结构的名称,键和结构中哈希表的名称,并定义函数以访问和修改哈希中键下的值.
(defmacro make-hash-accessor (struct-name key hash)
(let ((key-accessor (gensym))
(hash-accessor (gensym)))
`(let ((,key-accessor (accessor-name ,struct-name ,key))
(,hash-accessor (accessor-name ,struct-name ,hash)))
(setf (fdefinition ,key-accessor) ; reads
(lambda (instance)
(gethash ',key
(funcall ,hash-accessor instance))))
(setf (fdefinition '(setf ,key-accessor)) ; modifies
(lambda (instance to-value)
(setf (gethash ',key
(funcall ,hash-accessor instance))
to-value))))))
;; Returns the symbol that would be the name of an accessor for a struct's slot
(defmacro accessor-name (struct-name slot)
`(intern
(concatenate 'string (symbol-name ',struct-name) "-" (symbol-name ',slot))))
Run Code Online (Sandbox Code Playgroud)
为了测试这个,我有:
(defstruct tester
(hash …Run Code Online (Sandbox Code Playgroud)