Prolog 序言:通过回溯获得最大/最小值?

Prolog 序言:通过回溯获得最大/最小值?,prolog,max,min,Prolog,Max,Min,我想知道通过如下回溯获得某些事实的最大值(最年长者)是否是个好主意: data(MaxID, MaxName, MaxAge), \+ (data(ID, Name, Age), ID \= MaxID, MaxAge < Age). 这在空间或时间复杂性方面是否有效 实现的风格是否简单/直接?是否存在“更好”的实现 这在空间或时间复杂性方面是否有效 您的实现具有O(N^2)wrt时间复杂性,因为对于每个候选谓词,所有其他谓词都会被“调用”以进行比较。空间复杂度为O(1) 是否存在“更好

我想知道通过如下回溯获得某些事实的最大值(最年长者)是否是个好主意:

data(MaxID, MaxName, MaxAge),
\+ (data(ID, Name, Age), ID \= MaxID, MaxAge < Age).
这在空间或时间复杂性方面是否有效

实现的风格是否简单/直接?是否存在“更好”的实现

这在空间或时间复杂性方面是否有效

您的实现具有O(N^2)wrt时间复杂性,因为对于每个候选谓词,所有其他谓词都会被“调用”以进行比较。空间复杂度为O(1)

是否存在“更好”的实现

是的,存在更好、更高效的实现。很长一段时间以来,SWI Prolog提供了library(),这是对setof/bagof/findall经典内置项的直接增强:

?- aggregate(max(Age,data(ID,Name,Age)), ID^Name^data(ID,Name,Age), max(_,X)).
请注意由
ID^Name^…
表示的量化控制样式。这与setof/3和bagof/3的要求完全相同。基于不可回溯的分配,实现更加高效

可以将最新添加到库()。 在挖掘最后一个之前,请考虑使用库(聚合)。

编辑

基于@false comment to the question和@boris的答案,我将尝试提供一个“更好”(当然是主观评价)的实现:

min(P,A) :-
    copy_term(P,Q),
    arg(A,P,V), arg(A,Q,U),
    call(P), \+ ( call(Q), U@<V ).
min(P,A):-
复制_项(P,Q),
arg(A,P,V),arg(A,Q,U),

简单的回答是,不,没有什么比这更“好”的了,因为它总是正确的、易于实现的、高效的

一个小小的更正:写就足够了

data(MaxID, MaxName, MaxAge),
\+ (data(ID, Name, Age), MaxAge < Age)
只要您的
数据/3
只是一个事实表,就可以安全使用

当然,如果列表中有相等但不相等的元素,则会出现这种情况,如
数据(10,john,34)
数据(101,jane,34)
。在我链接的问答中有一些示例如何处理这种情况,但我真的不认为它变得“更好”。它可能会更有效。我强烈建议您仔细考虑您的用例,如果您认为这可能是一个瓶颈,请测量性能


查看@capelical所建议的列表,很明显,它正是针对该用例的:它可以在恒定内存中找到最小值、最大值、总和等,并且只触及每个事实一次,如果需要,可以返回到构建整个列表。

删除
ID\=MinID
使其速度更快。库的缺点(聚合):打破限制。另一个呢?只谈论你的编辑:另一个“好”的事情(非常主观)是如果库(聚合)将能够在不构建列表的情况下执行与foldl等效的操作。目前,它仅对硬编码的聚合函数集执行此操作:count、min、max。至少这是我从代码中得到的。当然,库(聚合)当您需要聚合时显示它的有用性。Sum不能用同一OP的样式来求解。那么,用一个语法来学习SQL提供的所有聚合函数(好的,或多或少)不是更好吗?@capelic绝对,我试图将手动使用bagof或findall与使用库(聚合)进行比较.我不完全明白你的意思…从所有指标来看,编写一个程序,即使是我们正在讨论的一个愚蠢的程序,在学习使用库之前似乎都不是一个好选择。这难道不是今天所有软件的基本属性吗?@capelical现在我不确定我是否理解你的意思。如果你是说学习使用库更有用是的,你自己做事情,但是选择库需要你从自己做事情中获得的理解。或者我没有领会你的意思吗?如果这是真的,那么就没有好的库存在:)
data(MaxID, MaxName, MaxAge),
\+ (data(ID, Name, Age), MaxAge < Age)
bagof(data(ID, Name, Age), data(ID, Name, Age), All),
sort(3, @>=, All, [data(Max_ID, Max_Name, Max_Age)|_])