GNU Prolog - проблема рекурсии (легко?) - PullRequest
4 голосов
/ 18 октября 2010

Хорошо, у меня есть это

edu_less(hs,college).
edu_less(college,masters).
edu_less(masters,phd).

Мне нужно написать функцию, чтобы сказать, если что-то меньше, чем другие.Предикат

edu_le.

Так что, если я поставлю edu_le(hs,phd)., он должен вернуть да.Я придумал это.

edu_le(A,B) :- A = B.
edu_le(A,B) :- edu_less(A,B).
edu_le(A,B) :- edu_less(A,C), edu_le(C,B).

Я действительно не хочу, чтобы он проходил через все и возвращал несколько ответов.

Можно ли вернуть только да или нет, если обнаружит, чтона самом деле он меньше или равен 2-му аргументу?

Так что, в принципе, если я снова воспользуюсь примером edu_le(hs,phd), то потому что hs меньше, чем колледж, а колледж меньше, чем магистры, а магистры меньше, чемphd, тогда hs должен быть меньше, чем phd, и он сказал бы, что да.

Извините, действительно новичок в прологе, все еще пытаюсь освоить это.

Ответы [ 4 ]

4 голосов
/ 18 октября 2010

В определении предиката

edu_le(A,B) :- A = B.
edu_le(A,B) :- edu_less(A,B).
edu_le(A,B) :- edu_less(A,C), edu_le(C,B).

второй пункт излишен и вызывает многократную генерацию ответов. Используйте

edu_le(A,B) :- A = B.
edu_le(A,B) :- edu_less(A,C), edu_le(C,B).

Это дает вам один true ответ, затем больше нет ответов (false) при возврате. Вы можете использовать вырез в первом предложении, но тогда генерация больше не будет работать.

?- edu_le(hs,X).
X = hs ;
X = college ;
X = masters ;
X = phd ;
false.

становится неполным:

?- edu_le(hs,X).
X = hs.

Как предложено, используйте вместо него once/1. В хорошей реализации Пролога этот предикат работает так, как будто ваша программа имеет сокращения в стратегических местах, ускоряя вашу программу, не нарушая ее логическую семантику.

3 голосов
/ 18 октября 2010

! / 0 также делает эту программу неполной, рассмотрим, например, самый общий запрос с обеими версиями:

?- edu_le(X, Y).

Часто лучше использовать один раз / 1, если вы хотите только одно доказательствоконкретная цель:

?- once(edu_le(hs, phd)).
3 голосов
/ 18 октября 2010

Наиболее практичный способ написания предикатов, подобных этому, - это использовать сокращение (!). Сокращение приводит к тому, что дополнительные пункты не учитываются при возврате. Вы бы написали свой предикат следующим образом:

edu_le(A,B) :- A = B, !.
edu_le(A,B) :- edu_less(A,B), !.
edu_le(A,B) :- edu_less(A,C), edu_le(C,B).

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

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

1 голос
/ 30 ноября 2012

Я бы посоветовал вам НЕ следовать по пути, предложенному Юхо Остманом, и сохранять чистоту - иначе зачем вам в первую очередь использовать Пролог? Если вы слишком мягко придерживаетесь логической парадигмы, вы получите неприятные результаты. В этом случае предикат Юхо определенно отличается от вашего, и я покажу вам, почему.

Во-первых, просто отбросьте бесполезное правило edu_le(A,B) :- edu_less(A,B)., как предполагает Ларсман. Вы получите менее избыточную версию вашего исходного предиката:

edu_le1(A, A).
edu_le1(A, B) :- edu_less(A, C), edu_le1(C, B).

Он просто ведет себя как edu_le, что означает: при произвольном запросе он выдает точно такой же ответ, за исключением дубликатов (edu_le1 имеет меньше). Вы можете просто быть довольны этим, но у него все еще есть некоторые лишние ответы, которые вам могут не понравиться; например, под SWI:

?- edu_le1(hs, hs)
true ;
false.

Теперь вы можете сказать, что вам это не нравится, потому что у него все еще есть избыточный false, но если вместо этого вы используете предикат Юхо (без бесполезного правила):

edu_le2(A, A) :- !.
edu_le2(A, B) :- edu_less(A, C), edu_le2(C, B).

это правда, что вы устраняете бесполезный финал false:

?- edu_le2(hs, hs)
true.

?-

но вы теряете больше, чем это: вы теряете, как замечено замечание, возможность генерации всех решений, когда не создается одна переменная:

?- edu_le1(hs, B) %same, with more copies, for edu_le
B = hs ;
B = college ;
B = masters ;
B = phd ;
false.

?- edu_le2(hs, B)
B = hs.           %bad!

?-

Другими словами, последний предикат НЕ эквивалентен первому: edu_le и edu_le1 имеют тип edu_le(?A, ?B), тогда как вместо edu_le2 имеет тип edu_le2(+A, +B) (значение см. В [1]). Будьте уверены: edu_le2 менее полезен, потому что он делает меньше вещей, и, следовательно, может быть повторно использован в меньшем количестве контекстов. Это потому, что вырез в edu_le2 является красным разрезом, то есть разрезом, который меняет значение предиката, в котором он вводится. Тем не менее, вы можете быть довольны этим, учитывая, что понимаете разницу между ними. Все зависит от того, что вы хотите с ним делать.

Если вы хотите получить лучшее из двух миров, вам нужно ввести в edu_le1 правильный зеленый срез, который снижает избыточность, когда A и B полностью созданы для условий. Для этой цели вы должны проверить, что A и B созданы для одного и того же срока перед резкой. Вы не можете сделать это с =, потому что = не проверяет, а объединяет. Правильный оператор: ==:

edu_le3(A, B) :- (A == B -> ! ; true), A = B.
edu_le3(A, B) :- edu_less(A, C), edu_le3(C, B).

Обратите внимание, что дополнительный разрез в первом правиле активен только тогда, когда A и B совпадают. Теперь, когда срез является правильным зеленым срезом, предикат работает и в самых общих случаях как исходный:

?- edu_le3(A, A).
true.

?- edu_le3(A, B).  %note that A and B are not the same term
A = B ;
A = hs,
B = college ;
A = hs,
B = masters ;
A = hs,
B = phd ;
A = college,
B = masters ;
A = college,
B = phd ;
A = masters,
B = phd ;
false.

?-

с возвратом Prolog по всем решениям.

Я не думаю, что есть какой-то способ исключить последние false без введения слишком сильной зависимости от edu_lt. Это потому, что мы должны держать в открытости возможность того, что есть еще 1048 * для изучения, в случае, если вы решите позже обогатить его более основательными фактами. Так что, на мой взгляд, это лучшее, что вы можете иметь.

[1] Справочное руководство SWI Prolog, раздел 4.1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...