Prolog-如何检查谓词是否多次成功
我有这样一个事实数据库:Prolog-如何检查谓词是否多次成功,prolog,Prolog,我有这样一个事实数据库: li(a,2). li(b,3). li(b,1). li(c,2). li(d,1). li(d,1). 我需要编写一个谓词more(+Let),如果它存在多个事实li(Let,u),则会成功 例如,查询more(b)和more(d)会成功,但more(a)和more(c)不会成功。 我的想法是检查李是否不止一次成功,但我不知道怎么做 试试看: 将d抽象出来并生成谓词是很简单的。对吧?:) 如果您不想使用任何谓词,如findall,您可以更改知识的表示形式-可以说
li(a,2).
li(b,3).
li(b,1).
li(c,2).
li(d,1).
li(d,1).
我需要编写一个谓词more(+Let),如果它存在多个事实li(Let,u),则会成功
例如,查询more(b)和more(d)会成功,但more(a)和more(c)不会成功。
我的想法是检查李是否不止一次成功,但我不知道怎么做 试试看:
将d
抽象出来并生成谓词是很简单的。对吧?:)
如果您不想使用任何谓词,如
findall
,您可以更改知识的表示形式-可以说,将其降低一个级别:
my_knowledge(li, [a-2,b-3,b-1,c-2,d-1,d-1]).
然后您可以使用SWI Prolog的谓词来处理它:
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 = [].
您可以将最后一个谓词重写为列表上的基本递归,然后在获得前N个结果后将其调整为停止。SWI Prolog has library()
测试:
学习起来并不容易,但处理这些普通任务很有用。如果您有一个非常大的代码库,那么findall(以及在内部使用findall的聚合)可能效率低下,构建一个列表只是为了计算它的元素
然后你们可以使用一个基于副作用的谓词:在相关的答案中你们会发现这样的效用。要获得最大效率,请参阅注释,其中说明了如何使用nb_setval/nb_getval
more_than_once(Goal) :-
\+ \+ call_nth(Goal,2).
使用中定义的调用第/2个
与提出的其他解决方案相比,该解决方案的最大优势在于,即使有非常大的答案序列,它也会迅速成功。事实上,它甚至会成功地找到无限多的答案:
?- more_than_once(repeat).
true.
?- more_than_once(between(1,100000,_)).
true.
?不止一次(重复)。
对。
?超过一次(在(1100000,)之间)。
对。
(调用第/2次调用的实现使用了一些非标准的、低级的SWI内置。这是可以避免的,但更令人头痛。)hmm,调用findall(X,pred(X),[[uu,| |]
可以理解为显示了将调用pred
的实际调用次数减少到不超过两次的意图。。。但这只能在执行层面上实现,对吗?或者它可能需要为谓词加上另一个名称,比如findsome
:)findall
毕竟说的是“全部查找”。您的解决方案看起来不错,但我正在搜索一个只使用谓词本身或基本谓词(如成员、追加、长度和明显的比较)的解决方案。@markusian那么您就不走运了。计算一个谓词成功的次数不是逻辑,而是逻辑之上的——也就是说,它不是关于证明某事,而是关于证明某事的机制的运作。至少您必须使用断言
/收回
,或标记
等。findall
更易于使用。感谢您的解释!因此,如果计算谓词成功的次数不是逻辑,我应该考虑另一种方法。@markusian,这就是使用标志
,或断言
/收回
,或findall
,或nb_setarg
的方法。编程语言的所有合法部分,Prolog。has sample成功\u n\u次
谓词。我刚刚发现我的问题比我想象的要简单,因为谓词more应该回答至少两个事实li(Let,X),li(Let,Y),X不等于Y。我简单地用more(L):-li(L,X),li(L,Y),X\=Y来解决它代码>
?- more(b).
true.
?- more(a).
false.
more_than_once(Goal) :-
\+ \+ call_nth(Goal,2).
?- more_than_once(repeat).
true.
?- more_than_once(between(1,100000,_)).
true.