假设我想找到谓词的所有解的总和,我可以使用
findall(L, find(L), Sols),
Run Code Online (Sandbox Code Playgroud)
并且只是总结了Sols的成员.
但是如果find(L)有很多(无限的,可能)解决方案,我只想得到它们中的前10个呢?
我希望它可用于B-Prolog和ECLiPSe CLP.
有许多类似的用途,因此可以考虑在两者之间定义一些抽象.例如call_firstn(Goal_0,N),最多可以获得第一批N许多答案Goal_0.这反过来可以使用call_nth(Goal_0, Nth).
findfirstn(N, Template, Goal_0, Instances) :-
findall(Template, call_firstn(Goal_0, N), Instances).
call_firstn(Goal_0, N) :-
N + N mod 1 >= 0, % ensures that N >=0 and N is an integer
call_nth(Goal_0, Nth),
( Nth == N -> ! ; true ).
Run Code Online (Sandbox Code Playgroud)
完全实现call_nth/2不泄漏但仍然是可重入的,不能直接在ISO Prolog中定义.你需要求助于各种低级操作,这些操作通常是不完整的语义,而这些语义对于常规程序员来说是更好的隐藏.
这就是你在ECLiPSe中的表现:
find_n(N, Term, Goal, Solutions) :-
( N < 1 ->
Solutions = []
;
record_create(Bag),
shelf_create(count(N), Counter),
(
once((
call(Goal),
recordz(Bag, Term),
\+shelf_dec(Counter, 1) % succeed if enough
)),
fail
;
recorded_list(Bag, Solutions)
)
).
Run Code Online (Sandbox Code Playgroud)
这是可重入的并且不会泄漏内存(两者都是全局变量或基于动态谓词的解决方案的问题).如果您希望它能够正确处理模块,则需要少量添加.
当然,您可以使用与Paulo使用的assert/retract原语相同的代码结构.
| 归档时间: |
|
| 查看次数: |
1529 次 |
| 最近记录: |