【发布时间】:2020-04-09 19:26:28
【问题描述】:
这是一个简单的问题。
has(steve, 5).
has(mark, 6).
has(craig, 4).
在 Prolog 中你如何知道谁拥有最多?
我试过has(Who, Max) 但这没有帮助。这里有可以用的算子吗?
谢谢。
【问题讨论】:
标签: prolog
这是一个简单的问题。
has(steve, 5).
has(mark, 6).
has(craig, 4).
在 Prolog 中你如何知道谁拥有最多?
我试过has(Who, Max) 但这没有帮助。这里有可以用的算子吗?
谢谢。
【问题讨论】:
标签: prolog
?- has(U,S),\+((has(V,T),T>S)).
U = mark,
S = 6 ;
false.
前缀运算符\+ 读作not。由于我们必须反证的是由中缀运算符, 表示的连词,因此需要使用双括号。
您应该知道,在使用它时,它是一种受限的否定形式,即所谓的negation as failure,由隐含在 Prolog 语义中的closed world assumption 实现。 p>
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 所指出的,我使用的语法不精确。实际上,双括号是\+ 被视为函子而不是运算符的结果。在符号后面加一个空格,我们可以改写
?- has(U,S),\+ (has(V,T),T>S).
【讨论】:
\+ 应读作“notfindany”。
has(U,S),\+ (has(V,T),T>S). 也有效,不能误认为是(二进制)谓词调用(注意\+ 后面的空格)。
\+。不过,它对not(...) 很满意。
aggregate 的解决方案,以补充another answer,其中包含基于not 和findall- 的代码,以及一个很好的复杂性讨论。在 cmets 中甚至讨论了 \+ 运算符之后的空格。 :)
\+==“没有证据表明...”。
试一试:
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.
【讨论】:
您可以使用标准谓词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 系统)。对于大量的事实,复杂性上的差异越来越明显。
【讨论】:
Names 具有相同的最大 Value。这也可以在整体 O(n) 中处理(当然在 n log n 排序之上),但情节变厚(代码复杂性爆炸)。 Prolog 应该是声明式魔法! (当然不是:)(但也许可以))。不同之处在于,基于not 的代码可能会在 O(n) 步骤之后产生它的第一个答案,但基于列表的代码会预先做更多的工作,所以不能。有趣的是,使用基于列表的方法,惰性语言将总是在O(n)中产生它的第一个答案...
findall/3(在我的解决方案和@Enigmativity 解决方案中)的调用是 O(n)。但是随后@Enigmativity 解决方案在列表中列出了解决方案 O(2*n)。但是解决方案也不是尾递归的,这会导致惩罚 w.r.t.空间复杂度。随着使用累加器使其尾递归的变化,它应该比其他解决方案更快。
findall/3 本身并对其进行调整以仅找到最大元素。自己在失败驱动的循环中做所有超逻辑的断言/撤回;即最手动编码。难道真的(已经)存在一个系统,它会进入战壕并自行为我们做这件事,所以我们可以坚持最高级别的声明性编码风格吗?....