Я новичок в Common Lisp и в качестве первого проекта работал над простым сопоставлением шаблонов. У меня возникли проблемы с использованием оператора звездочки (*) для представления 0 или более любых элементов в списке. Таким образом, шаблон (x * z) и сопоставитель (x y y y z) вернут true, но образец (x * z) и сопоставитель (x y) вернут false.
Мои первые мысли:
(loop for x in pattern-list
(eq x '*)
;if x is *, pause iterating through this list
(loop for y in matcher-list
;somehow iterate one more value in the pattern list
(eq x y) ;does the value just after the * in the pattern list equal the value in y?
;if they aren't the same symbol, just iterate matcher until they match, then resume incrementing though the pattern list
))
Извините, если мой синтаксис и скобки немного неправильны.
Это меньшая часть по сравнению с большим устройством сопоставления шаблонов, над которым я работал. Вот что у меня есть (в этом случае list1 - это список шаблонов, а список2 - список сопоставлений):
Большая часть этого кода возникла из этого сообщения SO:
Настройка одинаковой функции в общем lisp с использованием только "eq"
(defun comp-q (list1 list2) ;defun
(if (and (not (null list1)) ;if list1 is not null AND
(not (null list2))) ;if list2 is not null
(let ((a (car list1)) (b (car list2))) ;a is the car (front) of list1 and b is the car of list 2
(cond ((and (listp a) (listp b)) ;cond, evaluate the first thing in the list - are a and b lists?
(and (comp-q a b) ;recursive call on a and b
(comp-q (cdr list1) (cdr list2)))) ;recursive call on the cdr (tail) of a and b
(t ;like an else for cond
(and (or (eq a b) (eq a '?)) ;are a and b equal OR is a a '?'
(comp-q (cdr list1) (cdr list2)))))) ;recursive call on the cdr of a and b
(= (length list1) (length list2)))) ;are the lists equal? only triggered if the null test fails (are they both not null)
Лучше всего использовать макрос loop
? Можно ли «приостановить» или отслеживать итерации по списку (я знаю, что это похоже на массив)? Или я должен попытаться продолжить работу рекурсивно, вызывая car
и cdr
каждого списка, который реализуется в comp-q defun
?
Спасибо.
1 ответ
Поскольку никто еще не дал ответа и был предложен рекурсивный подход, я придумал пример в Racket, чтобы вы начали. Преобразование в Common Lisp должно быть простым.
(define (match pattern matcher)
; is the symbol a wildcard (i.e. does it end with an asterisk?
; yes -> return true + the symbol without the asterisk
; no -> return false + the symbol itself
(define (is-wildcard sym)
(let ((str (symbol->string sym)))
(if (string=? (substring str (sub1 (string-length str))) "*")
(values #t (string->symbol (substring str 0 (sub1 (string-length str)))))
(values #f sym))))
; we know wi is a wildcard; let's loop over matcher until done
(define (match-wildcard wi pattern matcher)
(if (empty? matcher)
(list (cdr pattern) matcher)
(if (eq? wi (car matcher))
(match-wildcard wi pattern (cdr matcher))
(list (cdr pattern) matcher))))
; main loop
(if (or (empty? pattern) (empty? matcher))
(and (empty? pattern )(empty? matcher))
(let ((pa (car pattern)) (ma (car matcher)))
(if (eq? pa ma)
(match (cdr pattern) (cdr matcher))
(let-values (((wildcard wi) (is-wildcard pa)))
(if wildcard
(apply match (match-wildcard wi pattern matcher))
#f))))))
Примеры:
(match '(x y* z) '(x y y y z))
=> #t
(match '(x z* y) '(x y))
=> #t
(match '(x y* z) '(x y))
=> #f
(match '(x y*) '(x y))
=> #t
HTH!
((eq a '*) ;is a a '*' (or (comp-q2 (cdr list1) list2 c) ;increment list1 but not list2 (comp-q2 list1 (cdr list2) c))) ;increment list2 but not list1
Похожие вопросы
Связанные вопросы
Новые вопросы
list
Тег списка может относиться к связанному списку (упорядоченный набор узлов, каждый из которых ссылается на своего преемника) или к форме динамического массива. Не использовать для списков HTML, используйте вместо этого [html-lists].
loop
. В противном случае для каждогоx
вpattern-list
вы будете перебирать весьmatcher-list
. Я рекомендую использовать рекурсивный подход, по крайней мере, для начала - он должен быть более интуитивным, чем использованиеloop
. Начнем с определения базового случая: учитывая списки, соответствует ли первый элементmatcher-list
шаблону? Если нет, потерпите неудачу; если да, примите первый элемент и рекурсивно вызовите с хвостами списков по мере необходимости.loop
для этого, вам нужно будет сказать, какие правила вы используете для сопоставления материалов. Подумайте о правилах CFG и PEG. Как вы решаете вопросы приоритета и выбора. Вы обязательно соответствуете самому длинному из возможных расширений или самому короткому и так далее. Я также хотел бы изучить библиотекуiterate
, потому что она позволяет переносить итерационные макросы. Кроме того, уже существует множество библиотек сопоставления шаблонов CL,optima
, по моему опыту, является хорошей.iterate
, потому что у него есть генераторы, что-то, что позволит вам продвигать итератор, управляющий циклом, что похоже на конкретную проблему, с которой вы столкнулись.