简短的回答是,不,就始终正确、易于实施和同时高效而言,没有什么真正“更好”的了。
一个小修正:写就够了
data(MaxID, MaxName, MaxAge),
\+ (data(ID, Name, Age), MaxAge < Age)
(正如@false 在对您问题的评论中所建议的那样)
你也可以看到this question and answers。 This answer 详细介绍了何时以及为什么使用 setof/3 可能会出现问题。它可能对您的用例很重要。
另一种方法(@CapelliC 非常有用的答案中未提及)是从您的谓词中收集所有解决方案并使用键对其进行排序。如果您使用的是 SWI-Prolog,或另一个具有 4-argument version of sort 的 Prolog,可让您在一个术语中选择比较和关键字,您可以这样做,例如:
bagof(data(ID, Name, Age), data(ID, Name, Age), All),
sort(3, @>=, All, [data(Max_ID, Max_Name, Max_Age)|_])
只要您的data/3 只是一个事实表,就可以安全使用。
如果列表中有相同但不相等的元素,这当然会分解,例如data(10, john, 34) 和data(101, jane, 34)。在我链接的问题和答案中,有一些如何处理这个问题的例子,但同样,我真的不认为它有任何“更好”。它可能更有效。我强烈建议您仔细考虑您的用例,并在您认为这可能是瓶颈时测量性能。
查看@CapelliC 建议的implementation of library(aggregate) 很明显,它完全适用于该用例:它可以在常量内存中找到最小值、最大值、总和等,并且只触及每个事实一次,然后回退必要时构建整个列表。