我有一个这样的事实数据库:
li(a,2).
li(b,3).
li(b,1).
li(c,2).
li(d,1).
li(d,1).
Run Code Online (Sandbox Code Playgroud)
如果它存在多个事实li(Let,_),我需要编写一个更成功的谓词(+ Let).
例如,更多(b)和更多(d)的查询将成功,但更多(a)和更多(c)将不会.我的想法是检查li(Let,_)是否不止一次成功,但我不知道该怎么做.
试试findall/3:
findall(X, li(d,X), L), length(L,N), N>1.
Run Code Online (Sandbox Code Playgroud)
抽象d出来并制作谓词是微不足道的.对?:)
如果您不想使用任何谓词findall,您可以更改您的知识表示 - 将其降低到一个级别,可以这么说:
my_knowledge(li, [a-2,b-3,b-1,c-2,d-1,d-1]).
Run Code Online (Sandbox Code Playgroud)
然后你可以使用SWI Prolog的谓词select/3来处理它:
select_knowledge(kn, key, R):-
my_knowledge(kn,L),
select_key(L,key,R).
select_key(L,K,R):-
select(K-X,L,L1) -> R=[X|R1], select_key(L1,K,R1)
; R = [].
Run Code Online (Sandbox Code Playgroud)
您可以将最后一个谓词重写为列表上的基本递归,然后在获得前N个结果后将其调整为停止.
more_than_once(Goal) :-
\+ \+ call_nth(Goal,2).
Run Code Online (Sandbox Code Playgroud)
与此答案中call_nth/2定义的一样.
与其他解决方案相比,该解决方案的最大优势在于,即使存在非常大的答案序列,它也能够快速成功.事实上,它甚至可以成功获得无限的答案:
?- more_than_once(repeat). true. ?- more_than_once(between(1,100000,_)). true.
(实现call_nth/2使用一些非标准的,低级别的SWI内置.可以避免这种情况,但更令人头痛.)