在我的函数中,我正在读取来自用户的输入,该输入应该是作为字符串给出的lisp形式,例如:
(sym1 sym2 (sym3 sym4))
我的目标是用其他符号替换某些符号,例如:
(sublis '((sym1 . sym1%)
(sym2 . sym2%))
str)
因为我将输入作为字符串获取,所以我首先将其转换为lisp表单。以下是最终函数的样子:
(defun sublis-when-string (str)
(sublis '((sym1 . sym1%)
(sym2 . sym2%))
(read-from-string str)))
当我编译函数并使用(sublis-when-string "(sym1 sym3 (sym2 sym4))")
在REPL中运行它时,我正确地得到:
(SYM1% SYM3 (SYM2% SYM4))
然而,当我运行整个程序时,替换不起作用:
(SYM1 SYM3 (SYM2 SYM4))
这让我相信问题与包装有关。当我在REPL中更改包时,替换仍然无效。
我的问题是:如何更改我的功能,以便在从其他软件包调用时可以正常工作?
答案 0 :(得分:4)
如果要独立于读取符号的包使用函数,可以通过添加显式测试来更改定义:当要检查的值是符号时,使用string=
运算符而不是默认eql
。例如:
(defun sublis-when-string (str)
(sublis '((sym1 . sym1%)
(sym2 . sym2%))
(read-from-string str)
:test (lambda (x y)
(if (and (symbolp x) (symbolp y))
(string= x y)
(eql x y)))))
请参阅sublis
的定义。
答案 1 :(得分:4)
您可以为您的用户定义一个包:
(defpackage :my-user (:use) (:export #:sym1 #:sym2))
当然,导出的符号是您需要在替换列表中添加的符号。然后,在阅读之前绑定*package*
变量:
(let ((*package* (find-package :my-user)))
(read-from-string string))
请注意,将从:my-user
包中读取所有符号。
根据您对字符串来源的信任程度,您还可以将*read-eval*
设置为nil并定义一个简约的可读表:
#n()
(错误的用户故意耗尽内存):
成为终止字符,以使符合条件的符号抛出错误(其他包中的用户实际符号不良)