这是一个简单的问题。
has(steve, 5).
has(mark, 6).
has(craig, 4).
在Prolog中,您如何从中获得最大收益?
我尝试了has(Who, Max)
,但这没有帮助。这里有可以使用的运算符吗?
谢谢。
答案 0 :(得分:5)
?- has(U,S),\+((has(V,T),T>S)).
U = mark,
S = 6 ;
false.
前缀运算符\+
读为非。由于我们必须反驳的是由中缀运算符,
表示的连词,因此必须使用双括号。
使用它时,您应该意识到它是一种限制否定形式,即所谓的negation as failure,它是由Prolog中隐含的closed world assumption使得语义。
max(U,S) :- has(U,S),notanybetterthan(S).
notanybetterthan(S) :- has(_,T),T>S,!,fail.
notanybetterthan(_).
或
max(U,S) :- has(U,S),\+anybetterthan(S).
anybetterthan(S) :- has(_,T),T>S.
编辑
正如@WillNess指出的那样,我使用的语法不精确。实际上,双括号是\+
的后代,被视为 functor ,而不是 operator 。我们可以在符号后面添加空格
?- has(U,S),\+ (has(V,T),T>S).
答案 1 :(得分:3)
您可以使用标准谓词findall/3
和keysort/2
:
| ?- findall(Value-Name, has(Name, Value), Pairs),
keysort(Pairs, SortedPairs).
Pairs = [5-steve, 6-mark, 4-craig],
SortedPairs = [4-craig, 5-steve, 6-mark]
yes
您想要SortedPairs
列表中的最后一对。只需遍历列表,直到到达其最后一个元素。我会留给您写一个last(List, Last)
谓词。
更新
Carlo的解决方案很惯用(+1)。但这也是O(n ^ 2)。我的解决方案(包括缺少的last/2
谓词)是O(2 * n + n * log(n))。另一方面,由于创建了临时列表,它对垃圾回收器的影响要稍微多一些。如果我们在OP中仅包含树事实,则Carlo的解决方案快约3倍。大约有100个事实,两种解决方案花费的时间大致相同(请注意,确切数字取决于所使用的Prolog系统)。对于许多事实,复杂性的差异变得越来越明显。
答案 2 :(得分:3)
尝试一下:
has(steve, 5).
has(mark, 6).
has(craig, 4).
?- findall(has(X, Y), has(X, Y), Z), maxhas(Z, has(Who, Max)), write([Who, Max]).
maxhas([has(X, Y)], has(X, Y)).
maxhas([has(_, Y)|Hs], has(A, B)) :- maxhas(Hs, has(A, B)), B >= Y.
maxhas([has(X, Y)|Hs], has(X, Y)) :- maxhas(Hs, has(_, B)), B < Y.
我得到:
[mark, 6]Yes.