【问题标题】:Dynamic Prolog predicate with incrementing component具有递增分量的动态 Prolog 谓词
【发布时间】:2024-01-01 01:54:01
【问题描述】:

我有一个由一组规则组成的知识库,当某些条件发生时,每个规则的头部都会执行复杂术语的断言或撤回。

如何确保Id 每次递增 assert(term(Id,A,B,C))?

【问题讨论】:

  • 是的,我会顺序
  • retract 怎么样?由此产生的“漏洞”应该如何处理?
  • 感兴趣的:SWI-Prolog Delimited continuations
  • @GuyCoder。 (1) 我认为“身份”标签没有帮助。 (2) “依次”是多余的。 “增加”是指“+1”;不是“+2”;不是“+1.5”。
  • @GuyCoder。不过,我确实看到您“按顺序”添加的一些优点。有点措辞问题……多个增量是按顺序进行的,但我认为不太可能产生误解。

标签: prolog global-variables swi-prolog prolog-assert


【解决方案1】:

假设您不关心Id 中的漏洞(在收回id_person/2 子句时发生),您可以这样做:

:- 动态 nextID/1。 :- 动态 id_person/2。 下一个 ID(0)。 assertz_person(P) :- 下一个 ID(I), 收回(nextID(I)), I1 是 I+1, 断言(nextID(I1)), 断言(id_person(I,P))。

示例使用(适用于 SWI-Prolog 8.0.0 和 SICStus Prolog 4.5.0):

?- id_person(I,P)。 错误的。 ?- assertz_person(joan), id_person(I,P)。 我 = 0,P = 琼。 ?- assertz_person(al)、assertz_person(ian)、id_person(I,P)。 我 = 0,P = 琼 ;我 = 1,P = 人 ; I = 2,P = 伊恩。

【讨论】:

  • assert/1 是旧版; assertz/1(或asserta/1)是标准的。此外,您可以通过使用 initialization/1 指令来初始化 current_id /1 谓词来避免 if-then-else 构造。
  • @PauloMoura。对!旧习惯:) 初始化指令(在这种情况下)是否比一个简单的事实更好? (这是一个附加概念。)
  • 我认为你不需要两个nextID(I), retract(nextID(I)),我认为retract(nextID(I)) 就足够了。
  • @DanielLyons。好主意。但是 SICStus 手册 (sicstus.sics.se/sicstus/docs/latest4/html/sicstus.html/…) 让我有点不安,明天会检查一下。谢谢!
  • 这将是有问题的 if nextID/1 是不确定的,但如果没有线程,它应该只有一个解决方案。如果你有线程,那么无论如何你还有其他问题(你需要一个临界区或一个锁)。
【解决方案2】:

当您为第一个参数是唯一(整数)标识符的 term/3 谓词断言子句时,不需要辅助动态谓词来表示当前计数器。你可以简单地这样做:

:- dynamic(term/3).

assert_term(A, B, C) :-
    (   term(Id, _, _, _) ->
        NextId is Id + 1
    ;   NextId is 1
    ),
    asserta(term(NextId, A, B, C)).

asserta/1 的调用将使term/3 的最新断言子句在调用时成为第一个被检索的子句,如上所述,所有参数都未绑定,从而提供对最后计数的访问。但是,此解决方案假定条款不会被任意撤回。

【讨论】: