我试图找出是否有一种简单的方法可以在Common Lisp中混合使用SUBLIS
和反引号,而无需自己编写。
常规SUBLIS
会给我以下结果:
CL> (sublis '((X . (1 2 3))) '(bar (foo X)))
(BAR (FOO (1 2 3)))
(一般情况可以是任意复杂的树,而不仅仅是一个简单的列表。)
但我正在寻找一个将列表拼接成替换的版本,例如:
CL> (sublis1 '((X . (1 2 3))) '(bar (foo X)))
(BAR (FOO 1 2 3))
就像它发生在反引号和逗号上一样:
CL> (let ((x (list 1 2 3))) `(bar (foo ,@x)))
(BAR (FOO 1 2 3))
答案 0 :(得分:4)
据我所知,没有标准功能可以做到这一点。
如果splice变量始终是列表的结尾,您可以使用:test #'equal
,如下所示:
(sublis '(((x) . (1 2 3)))
'(bar (foo x))
:test #'equal)
=> (BAR (FOO 1 2 3))
对于其他任何事情,sublis
的结构变化都太难了。
但是,写作并不难,因为我在编写实现时出现的答案显示了。
答案 1 :(得分:4)
说到不重新发明轮子,你可以使用Common Lisp实现附带的代码漫游器(如果有的话)。例如 在SBCL中,FOO明确的简单替换可以如下进行:
(sb-walker:walk-form '(bar (foo X))
nil
(lambda (form context env)
(declare (ignore context env))
(if (equal form '(foo x))
'(foo 1 2 3)
form)))
但是,在你的情况下,你想要匹配X,而不是FOO。它并不多 更难,但让我们使用模式匹配库 OPTIMA来说明它是如何运作的:
(sb-walker:walk-form '(bar (foo X))
nil
(lambda (form context env)
(declare (ignore context env))
(optima:match form
((list head 'x) (list head 1 2 3))
(_ form))))
这里没有进入无限步行的风险,因为(foo 1 2 3)
无法匹配第一条规则。但是,您可能想要提供
T的次要值,以防止步行者进入
结果形式。
答案 2 :(得分:3)
没有标准的CL功能可以做到这一点; (替代等人只在序列上工作,而不是在树上工作;替代等人在树上工作,但只替换固定的新工作。)
唯一不这样做的方法是使用可以执行此操作的库,或者更多。我只能想到一些模式匹配库。
也许你可以查找一些代码来实现你必须实现的相同的东西,并运气好,找到并找到你想要的相同功能。
但老实说,找到一个模式匹配库并学习如何使用它来做你想做的事情,或者找到一个已经实现过的功能的类似程序,这看起来比我编程更多,工作量也很少。甚至在stackoverflow上询问看起来比写它更多的工作!
(defun sublis1 (bindings tree)
(cond
((null tree) tree)
((atom tree) ;; a dotted list in the tree.
(cdr (assoc tree bindings)))
((let ((entry (assoc (car tree) bindings)))
(when entry
(append (cdr entry) (sublis1 bindings (cdr tree))))))
((atom (car tree))
(cons (car tree)
(sublis1 bindings (cdr tree))))
(t
(cons (sublis1 bindings (car tree))
(sublis1 bindings (cdr tree))))))
(sublis1 '((X . (1 2 3))) '(bar (foo X)))
--> (bar (foo 1 2 3))