Reputation: 81
I'm trying to write a function which compare two lists in Common Lisp.
The sign ’&’ indicates any sequence of elements and the sign ’$’ indicates any single element.
(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)))))
which works fine :
(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
I would like to add a new filter (with the% symbol) which allows the choice between different possible elements, for example
(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
Upvotes: 3
Views: 803
Reputation: 1934
You have to try all the elements in the sublist after % to see if any of them, combined with the rest of the filter, matches the data:
(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)))))
You should also add some checking steps to ensure that the filter is correctly formed, i.e. that the element after % is a list, etc...
Upvotes: 7