【问题标题】:Prolog database with automatic retraction on backtracking回溯时自动撤回的 Prolog 数据库
【发布时间】:2013-03-15 12:09:33
【问题描述】:

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

类似的东西可以表示为

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

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

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

【问题讨论】:

    标签: prolog


    【解决方案1】:

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

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

    【讨论】:

    • 有趣 (+1),然而,完全以连续传递风格重写程序是一个挑战 :)。
    【解决方案2】:

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

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

    【讨论】:

    • 据我了解,逻辑状态线程只是允许以更方便的方式将数据库建模为“作为数据结构”(以某种形式表示“所有断言事实的列表”)? “线程”允许不通过所有谓词传递相应的参数(表示“旧”和“新”数据库状态),隐式定义此参数(?)。如果是这样,那就是我想要避免的(即使用通过参数传递的某些数据结构对数据库进行建模)。但是,无论如何,这是一项有趣的技术,所以感谢您的参考(+1)
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      在 SWI-Prolog 中,backtrackable assert 可以通过内置谓词 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.
      

      【讨论】:

        猜你喜欢
        • 2018-07-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多