2016-04-19 53 views
4

我试图找出是否有这样做的SUBLIS和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)) 

就像它发生在反引号和逗号ATSIGN:

CL> (let ((x (list 1 2 3))) `(bar (foo ,@x))) 
(BAR (FOO 1 2 3)) 

回答

3
  1. 有没有标准CL函数来做到这一点; (替代等人仅在序列树工作,而不是; SUBST等人的树工作,但仅替换一个固定新)。

  2. 不这样做的唯一方法,是使用将做到这一点,或更多的图书馆。我只能想到一些模式匹配库。

也许你可以查找一些代码来实现你必须实现的同样的事情,并且有一些运气,找到并找到你想要的相同功能。但是老实说,找到一个模式匹配库并学习如何使用它来做你想做的事,或者找到一个类似的程序来实现这个已经实现的功能,这让我看起来更多的工作,以及比编程它更少的乐趣。甚至要求在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)) 
+0

每一段代码可以有错误,如果存在一个核心功能来完成这项工作,这将是更好的使用它,而不是写一个新的。这是问题的真正原因。我们都可以想出编写函数sublis1的方法。 –

+0

没错,对不起,没有说清楚:这个想法是不是索取sublis1'的'实现(我想象它不会是困难的),而是看是否有一个简单的解决方案在那里,战斗测试等不管怎么说,感谢您的实施! –

4

据我所知,没有标准的功能来做到这一点。 如果拼接变量始终是一个列表的末尾,你可以使用:test #'equal像这样:

(sublis '(((x) . (1 2 3))) 
     '(bar (foo x)) 
     :test #'equal) 

=> (BAR (FOO 1 2 3)) 

为别的结构的变化是sublis太难了。 这不是太难写,不过,因为这似乎当我在写一个实施显示了答案。

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以防止助手缓存到结果表单中。