Рекурсивная функция в Лиспе

Мне нужно построить функцию, которая определяет, есть ли у меня соединение правильных формул, построенных таким образом:

cong ::= '(' и wff wff ...')'

Предположим, у меня есть код, который определяет, является ли формула wff. Функция должна сначала проверить, является ли первый элемент списка 'and, а затем рекурсивно проверить остальные подсписки, если они являются wff. Обратите внимание, что p также является wff, поэтому он не обязательно должен быть подсписком.

Пример: (and (or a b v) (and a b d) m n)

Вот что я пробовал, что не работает для меня:

(defun cong (fbf)
    (and (eq (first fbf) 'and )
        (reduce (lambda (x y) (and x y))
            (mapcar #'wff (rest fbf)))))

person Ester Vojkollari    schedule 12.02.2013    source источник
comment
Что он делает, когда вы его запускаете?   -  person ckb    schedule 12.02.2013
comment
CL-USER 27 : 7 › (cong '(и a b c d)) Ошибка: невозможно взять CAR для A.   -  person Ester Vojkollari    schedule 12.02.2013


Ответы (1)


Если предположить, что предикат wff работает, ваш код будет работать. Например, используя numberp в качестве предиката:

(defun cong (fbf)
  (and (eq (first fbf) 'and)
       (reduce (lambda (x y) (and x y))
               (mapcar #'numberp (rest fbf)))))

Работает отлично:

CL-USER> (cong '(and 1 2 3 4 5))
T
CL-USER> (cong '(and 1 2 3 4 foo))
NIL
CL-USER> (cong '(1 2 3 4))
NIL

Обратите внимание, что это можно сделать проще:

(defun cong (fbf)
  (and (eq (first fbf) 'and)
       (every #'wff (cdr fbf))))

Также обратите внимание, что в CL по соглашению предикаты обычно должны заканчиваться на p.

Итак, ваша, учитывая ваш комментарий выше, ваша проблема заключается в предикате wff, который, похоже, не работает для атомов. Поскольку вы упомянули, что p удовлетворяет wff, этот предикат совершенно неверен, но если вам нужно его использовать (при условии, что это какое-то домашнее задание), просто проверьте, не является ли имеющийся элемент минусом:

(defun cong (fbf)
  (and (eq (first fbf) 'and)
       (every #'wff (remove-if-not #'consp (cdr fbf)))))

Это предполагает, что каждый атом удовлетворяет wff. Таким образом, они не изменят исход соединения и могут быть опущены. В противном случае вам пришлось бы написать еще один предикат для проверки атомов, удовлетворяющих wff, или, что было бы правильно, исправить wff в первую очередь.

Кроме того, обратите внимание, что все это на самом деле не связано с рекурсией, поскольку вы только спрашиваете, как применить предикат к списку и получить конъюнкцию результатов.

person danlei    schedule 12.02.2013
comment
Ну, я не понимаю, как wff может быть неправильным. Этот предикат должен проверять, правильно ли сформирована формула и основана ли она на вызове других функций. Вот как это определяется: pastebin.com/VMDExFt1 и вот поддерживаемая им грамматика pastebin.com/jTpFw0bp - person Ester Vojkollari; 12.02.2013
comment
Что ж, в fbf-fun predicato оценивается после предикатов, которые работают со списками. Например, negazione принимает car своего аргумента без предварительной проверки, является ли он вообще списком. Сначала вам нужно проверить, является ли аргумент минусом, иначе эти тесты не сработают. - person danlei; 12.02.2013
comment
Мне жаль, но я не понимаю. Что вы имеете в виду, что predicato оценивается после предикатов, которые работают со списками. Я знаю, что negazione берет машину своего аргумента без предварительной проверки, является ли это списком, но когда negazione терпит неудачу, не должен ли оператор или в fbf-fun попытаться оценить оставшиеся предикаты, такие как cong, disg и т. д.? - person Ester Vojkollari; 12.02.2013
comment
Дело в том, что это не сопоставление с образцом в стиле ML. Код для negazione будет запущен независимо от того, является ли его аргумент списком или нет, поэтому он попытается взять car атома, если это был его аргумент. Однако применение car к атому будет сигнализировать о необработанном type-error. Ваш предикат никогда не возвращается, и поэтому другие ветки or не будут выполняться. - person danlei; 12.02.2013
comment
Пожалуйста. Возможно, вам стоит потратить время на то, чтобы снова прочитать несколько основ Лиспа. С одной стороны, ваш код выглядит нормально, используя reduce, mapcar и т. д. — с другой стороны, у вас, похоже, есть несколько проблем с базовыми правилами вычисления. - person danlei; 12.02.2013
comment
давайте продолжим это обсуждение в чате - person Ester Vojkollari; 12.02.2013