sublis在从另一个包中调用时不替换符号

时间:2016-11-15 10:51:22

标签: lisp common-lisp

在我的函数中,我正在读取来自用户的输入,该输入应该是作为字符串给出的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中更改包时,替换仍然无效。

我的问题是:如何更改我的功能,以便在从其他软件包调用时可以正常工作?

2 个答案:

答案 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()(错误的用户故意耗尽内存)
  • 使:成为终止字符,以使符合条件的符号抛出错误(其他包中的用户实际符号不良)