Common Lisp - Pattern Matching - PullRequest
       36

Common Lisp - Pattern Matching

3 голосов
/ 21 января 2020

Я пытаюсь написать функцию, которая сравнивает два списка в Common Lisp.

Знак '&' указывает на любую последовательность элементов, а знак '$' указывает на любой отдельный элемент.

(defun match (filter data)
     (cond
        ((atom filter) (eq filter data))
        ((atom data) NIL)
        ((eq (car filter) '|$|)
           (match (cdr filter) (cdr data)))
        ((eq (car filter) '|&|)
           (cond
             ((match (cdr filter) data))
             (data (match filter (cdr data)))))
        ((match (car filter) (car data))
            (match (cdr filter) (cdr data)))))

, который работает нормально:

(match '(a b c) '(a b c)) ; => T
(match '(a $ c) '(a b c)) ; => T
(match '(a ff c) '(a b c)) ; => NIL
(match '(a & c) '(a z b c)) ; => T

Я хотел бы добавить новый фильтр (с символом%), который позволяет выбирать между различными возможными элементами, например

(match '(a %(b 1) c) '(a b c)) ; => T
(match '(a %(b 1) c) '(a 1 c)) ; => T
(match '(a %(b 1) c) '(a z c)) ; => NIL

1 Ответ

7 голосов
/ 21 января 2020

Вы должны попробовать все элементы в подсписке после%, чтобы увидеть, соответствует ли какой-либо из них в сочетании с остальной частью фильтра данными:

(defun match (filter data)
     (cond
        ((atom filter) (eq filter data))
        ((atom data) NIL)
        ((eq (car filter) '|$|)
           (match (cdr filter) (cdr data)))
        ((eq (car filter) '|&|)
           (cond
             ((match (cdr filter) data))
             (data (match filter (cdr data)))))
        ((eq (car filter) '|%|)
          (some #'(lambda (f) (match (cons f (cddr filter)) data)) (cadr filter)) )
        ((match (car filter) (car data))
            (match (cdr filter) (cdr data)))))

Вы также должны добавить некоторые шаги проверки чтобы убедиться, что фильтр сформирован правильно, то есть, что элемент после% является списком, et c ...

...