是否有任何支持可伸缩数据库的 Prolog 实现?我的意思是当序言引擎通过该谓词调用回溯时,数据库会自动撤回由 assert() 谓词调用插入的事实?换句话说,我希望在回溯时“自动”隐式撤回。
类似的东西可以表示为
my_assert(Fact):- assert(Fact).
my_assert(Fact):- retract(Fact), fail.
但这在通过切割回溯时无法正常工作(!)
或者可以使用 Prolog 的“表格”风格以某种方式实现这个目标?
是否有任何支持可伸缩数据库的 Prolog 实现?我的意思是当序言引擎通过该谓词调用回溯时,数据库会自动撤回由 assert() 谓词调用插入的事实?换句话说,我希望在回溯时“自动”隐式撤回。
类似的东西可以表示为
my_assert(Fact):- assert(Fact).
my_assert(Fact):- retract(Fact), fail.
但这在通过切割回溯时无法正常工作(!)
或者可以使用 Prolog 的“表格”风格以某种方式实现这个目标?
我不知道任何原生支持您想要的 Prolog 实现。您可以在setup_call_cleanup/3之上使用延续传递样式实现类似的东西:
% assert Fact while seeking Goal then retract Fact
assert_then(Fact, Goal) :-
setup_call_cleanup(assert(Fact), Goal, retract(Fact)).
:- dynamic whom/1.
example :-
assert_then(whom(world), hello).
hello :-
whom(Whom),
format('Hello ~w~n', [Whom]).
这有点难看,但应该与回溯、异常和剪切一起使用。
这个库可能对你有用https://github.com/tef/nomads
它使用各种 prolog 术语重写技巧来模拟向所有包含断言事实的谓词添加附加参数。
在 SWI-Prolog 中,可回溯的断言可以使用内置的谓词来实现undo/1
:
b_assertz(Term) :-
assertz(Term, Ref),
undo(erase(Ref)).
没有剪切的例子:
?- between(1,2,X), b_assertz(p(X)), between(3,4,Y), b_assertz(p(Y)), listing(p).
:- dynamic p/1.
p(1).
p(3).
X = 1,
Y = 3 ;
:- dynamic p/1.
p(1).
p(4).
X = 1,
Y = 4 ;
:- dynamic p/1.
p(2).
p(3).
X = 2,
Y = 3 ;
:- dynamic p/1.
p(2).
p(4).
X = 2,
Y = 4.
?- p(X).
false.
切割示例:
?- between(1,2,X), b_assertz(p(X)), !, between(3,4,Y), b_assertz(p(Y)), listing(p).
:- dynamic p/1.
p(1).
p(3).
X = 1,
Y = 3 ;
:- dynamic p/1.
p(1).
p(4).
X = 1,
Y = 4.
?- p(X).
false.
Necro,但我有同样的问题,我尝试了 nb_setval 和 b_setval 的组合。它似乎适用于更简单的情况,但我还没有在更难的情况下进行测试。主要区别在于您不能直接查询 b_assert'ed 事实,而必须使用 b_query。
:- dynamic b_asserted/2.
:- nb_setval(b_assert_nbc, 0), nb_setval(b_assert_bc, 0).
b_assert(What):-
b_assert_maintain_consistency,
b_getval(b_assert_nbc, NBC),
AssertId is NBC+1,
assert(b_asserted(AssertId, What)),
nb_setval(b_assert_nbc, AssertId),
b_setval(b_assert_bc, AssertId).
b_query(What):-
b_assert_maintain_consistency,
b_asserted(_, What).
% The overhead
b_assert_maintain_consistency:-
nb_getval(b_assert_nbc, NBC),
b_getval(b_assert_bc, BC), % BC < NBC if backtracking happened
b_assert_restore_consistency(BC, NBC).
b_assert_restore_consistency(C, C):- !.
b_assert_restore_consistency(BC, NBC):-
BC1 is BC+1,
(between(BC1, NBC, DeleteMe), retract(b_asserted(DeleteMe, _)), fail; true),
nb_setval(b_assert_nbc, BC).
如果这可行,奖金将是找出 b_retract。也许我们 b_assert(b_retracted(What)) 并在 b_query 中重放断言和撤回?