当我运行查询时,它可以返回零,一个或多个结果。如何“保存”这些结果以便我以后可以比较它们,或者我如何在运行中比较它们?
例如,我有这些事实:
father(john, mark).
father(john, michael).
age(michael, 10).
age(mark, 12).
现在,如果我运行这样的查询
?- father(john, X).
它会返回mark
和michael
,但如何比较mark
和michael
的年龄?实际上,我怎么能知道查询会返回多个结果?
我的想法是,我想得到父亲的长子
答案 0 :(得分:2)
你在这里遇到的事实是,在回溯时,Prolog会释放它在产生前一个结果时发现的变量绑定。这个功能在早期引起了很多惊愕,所以知道你并不孤单,我们都曾经在那里。
你应该做的第一件事是尽量放弃告诉Prolog如何获得结果的需要,而是专注于告诉Prolog如何区分你想要的逻辑结果。毕竟这是逻辑编程。 :)当你说“我怎样才能比较mark
和michael
的年龄?”你隐藏了一个真实的问题,假设一旦你知道如何抓住事物,你就可以自己找到答案。但你不想自己找到答案,你希望Prolog找到它!
我们举一个例子。假设你想知道谁是谁中最小的孩子。你可以逻辑地做到这一点:
?- father(Father, Child),
age(Child, YoungestAge),
\+ (father(Father, Child2),
age(Child2, Younger),
Younger < YoungestAge).
Father = john,
Child = michael,
YoungestAge = 10.
遗憾的是,这对于大型数据库来说效率很低,因为Prolog必须搜索每个age/2
事实以找到特定父级的所有子级。据推测,Prolog会将这些谓词编入索引,这可能足以根据您的使用方式来拯救我们,但它看起来并不像您可以普遍应用的策略。但是你无法击败这个问题的逻辑阅读:假设我有一个父亲孩子的父亲,并且假设孩子的年龄是最年轻的,那么同一个父亲的孩子2的年龄比最年轻的年轻。
通常,您确实需要所有解决方案,因此有三个谓词:setof/3
,bagof/3
和findall/3
。它们都具有基本相同的API,语义略有不同。例如,如果您想要父母的所有孩子,您可以使用setof
来获取它们:
?- setof(Child, father(john, Child), Children).
Children = [mark, michael].
你需要一个更大的事实数据库才能看到两者之间差异的影响,但这是一个不同的问题。简而言之,setof/3
将为您提供唯一答案的排序列表,而bagof/3
将为您提供包含所有答案的未排序列表。 findall/3
做同样的事情,它对待变量的方式不同。根据我的经验,setof/3
和findall/3
的使用频率往往超过bagof/3
。
如果您正在进行的工作需要它,或者效率需要它,您可以使用这些元谓词来查找所有可能的解决方案,并在列表中执行您需要执行的任何处理。
关于“我怎么能知道查询会返回多个结果?”的问题。答案基本上是你可以生成它们并查看你有多少(findall(..., Answers), length(Answers, Count)
),或者你可以使用once/1
来确保你得到一个解决方案。 once
非常适合使非确定性谓词具有确定性;效果与在条款之后立即进行切割基本相同。例如:
?- father(john, X).
X = mark ;
X = michael.
?- once(father(john, X)).
X = mark.
?- father(john, X), !.
X = mark.
一般情况下,如果可能,建议您使用once/1
而不是显式剪切。
如果有帮助,请告诉我。
答案 1 :(得分:1)
只是丹尼尔回答的一个脚注:
eldest(Father, Child) :-
findall(A/C, (father(Father, C), age(C, T), A is -T), L),
sort(L, [_/Child|_]).
我使用否定年龄的技巧以相反的顺序获取列表。
这里的'one liner'与上面的内容完全相同:
eldest(Father, Child) :-
setof(A/C, T^(father(Father, C), age(C, T), A is -T), [_/Child|_]).
如果您的Prolog有库(aggregate),编辑,有一种更简洁的方式来获得结果:
eldest(Father, Child) :-
aggregate(max(A, C), (father(Father, C), age(C, A)), max(_, Child)).