好的,我有这个
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).
我真的不希望它通过所有内容并返回多个答案。
如果它发现它实际上小于或等于第二个参数,是否可以只返回yes或no?
所以基本上如果我再次使用示例edu_le(hs,phd)
,那么因为hs不是大学,而大学不是大师,而且大师不是博士,那么hs必须小于博士,它会说是
对不起,prolog真的很新,仍然试图掌握这一点。
答案 0 :(得分:4)
在谓词定义中
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
。在一个很好的Prolog实现中,这个谓词就好像你的程序在战略位置有所削减,加速你的程序而不会打扰它的逻辑语义。
答案 1 :(得分:3)
编写类似谓词的最实用的方法是使用cut(!)。这种削减导致在回溯时不考虑进一步的条款。您可以将谓词编写如下:
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 :(得分:3)
!/ 0也使该程序不完整,例如考虑两个版本的最常规查询:
?- edu_le(X, Y).
如果您只想要一个特定目标的单一证明,通常最好使用一次/ 1:
?- once(edu_le(hs, phd)).
答案 3 :(得分:1)
我建议你不要遵循JuhoÖstman提出的路径并保持纯度 - 否则,为什么你应该首先使用Prolog?如果你对遵守逻辑范式过于宽容,那么你会得到一些不愉快的结果。在这种情况下,Juho的谓词肯定与你的不同,我会告诉你原因。
首先,正如larsmans所暗示的那样,放弃无用的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
,但如果你使用Juho的谓词(没有无用的规则):
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
。这是因为我们必须保持有另外edu_lt
探索的可能性,如果您稍后决定用更多基础事实来丰富它。所以,在我看来,这是你能做到的最好的。
[1] SWI Prolog参考手册,第4.1节。