Je vous suggère de ne pas suivre le chemin proposé par Juho Östman et garder la pureté - sinon, pourquoi devriez-vous utiliser Prolog en première instance? Si vous êtes trop indulgent pour vous en tenir au paradigme logique, vous obtenez des résultats déplaisants. Dans ce cas, le prédicat de Juho est définitivement différent du vôtre, et je vais vous montrer pourquoi. Tout d'abord, il suffit de supprimer la règle inutile edu_le(A,B) :- edu_less(A,B).
, comme le suggère larsmans. Vous obtiendrez une version moins redondante de votre prédicat d'origine:
edu_le1(A, A).
edu_le1(A, B) :- edu_less(A, C), edu_le1(C, B).
Il se comporte comme edu_le
, ce qui signifie: étant donné une requête arbitraire, elle produit exactement la même réponse, à l'exception des doublons (edu_le1
a moins). Vous pouvez juste être heureux avec lui, mais il a encore des réponses redondantes que vous n'aimez peut-être pas; par exemple, sous SWI:
?- edu_le1(hs, hs)
true ;
false.
Maintenant, vous pouvez dire que vous ne l'aimez pas, car il a toujours le false
redondant, mais si vous utilisez le prédicat au lieu de Juho (sans la règle inutile):
edu_le2(A, A) :- !.
edu_le2(A, B) :- edu_less(A, C), edu_le2(C, B).
il est vrai que vous éliminez l'inutile finale false
:
?- edu_le2(hs, hs)
true.
?-
mais vous perdez plus que cela: vous perdez, comme le remarque mat, la possibilité de générer tous les e e solutions quand une variable ne sont pas instanciés:
?- 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!
?-
En d'autres termes, ce dernier prédicat ne correspond pas à l'ancienne: edu_le
et edu_le1
avoir le type edu_le(?A, ?B)
, alors au lieu edu_le2
a le type edu_le2(+A, +B)
(voir [1] pour la sens). Soyez sûr que: edu_le2
est moins utile car il fait moins de choses, et peut donc être réutilisé dans moins de contextes. Ceci parce que la coupe en edu_le2
est une coupe en rouge, c'est-à-dire une coupe qui change la signification du prédicat où elle est introduite. Vous pouvez néanmoins vous en contenter, étant donné que vous comprenez la différence entre les deux. Tout dépend de ce que vous voulez faire avec.
Si vous voulez obtenir le meilleur des deux mondes, vous devez introduire dans edu_le1
une coupe verte appropriée qui réduit la redondance lorsque A et B sont complètement instanciés. Dans ce but, vous devez vérifier que A et B sont instanciés au même terme avant de couper. Vous ne pouvez pas le faire avec =
, car =
ne vérifie pas, mais unifie. L'opérateur droit est ==
:
edu_le3(A, B) :- (A == B -> ! ; true), A = B.
edu_le3(A, B) :- edu_less(A, C), edu_le3(C, B).
Notez que la réduction supplémentaire de la première règle est active uniquement lorsque A
et B
arriver à être le même terme. Maintenant que la coupe est une coupe verte appropriée, le prédicat fonctionne aussi dans les cas les plus généraux comme l'original:
?- 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.
?-
avec Prolog retours en arrière à travers toutes les solutions.
Je ne pense pas qu'il existe un moyen d'éliminer le dernier false
sans introduire trop de dépendance sur edu_lt
. Ceci parce que nous devons garder ouvert la possibilité qu'il y a un autre edu_lt
à explorer, dans le cas où vous décidez plus tard de l'enrichir avec plus de faits au sol. Donc, à mon avis, c'est le meilleur que vous pouvez avoir.
[1] Manuel de référence SWI Prolog, section 4.1.
AHHHHHHH (comme une sainte ahhh). Je vous remercie. Dieu merci, je ne suis pas un puriste, n'est-ce pas? – Matt