5

是否有任何支持可伸缩数据库的 Prolog 实现?我的意思是当序言引擎通过该谓词调用回溯时,数据库会自动撤回由 assert() 谓词调用插入的事实?换句话说,我希望在回溯时“自动”隐式撤回。

类似的东西可以表示为

my_assert(Fact):- assert(Fact).
my_assert(Fact):- retract(Fact), fail.

但这在通过切割回溯时无法正常工作(!)

或者可以使用 Prolog 的“表格”风格以某种方式实现这个目标?

4

4 回答 4

2

我不知道任何原生支持您想要的 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]).

这有点难看,但应该与回溯、异常和剪切一起使用。

于 2013-03-16T15:05:26.243 回答
1

这个库可能对你有用https://github.com/tef/nomads

它使用各种 prolog 术语重写技巧来模拟向所有包含断言事实的谓词添加附加参数。

于 2013-03-15T12:35:57.753 回答
0

在 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.
于 2022-02-07T00:05:05.473 回答
0

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 中重放断言和撤回?

于 2021-01-19T13:16:19.933 回答