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