2016-04-19 2 views
4

Я пытаюсь выяснить, есть ли простой способ сделать смесь SUBLIS и backquote в 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, чтобы сделать это; (substitute et al. работают только над последовательностями, а не по дереву; 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, чтобы не допустить, чтобы ходок возвращался в итоговую форму .

Смежные вопросы