【问题标题】:Alternative to findallfindall 的替代品
【发布时间】:2015-03-23 18:39:08
【问题描述】:

我正在尝试在 Prolog 中创建 findall 的替代方案。

我拥有的是:

solutions(A,T,S) :- 
   T,
   assert(temp(A)),
   fail.
solutions(A,T,S) :-
   obtain([],S).

obtain(X,S) :-
   retract(temp(A)),
   obtain([A|X],S).
obtain(S,S).

然而,这给了我不一致的结果。怎么了?提前谢谢你。

【问题讨论】:

  • 您能描述一下您的结果中有什么不一致吗?
  • 也许使用assertz 而不是assert 可以解决这个神秘的不一致问题。
  • @EugeneSh。我相信assertassertz 做同样的事情。 :)
  • @lurker 会断言保证追加到末尾吗?我找不到任何提及它的东西..
  • @EugeneSh。如果它是 SWI Prolog,那么我相信它从assert/1 is deprecated in favor of assertz/1 开始就可以了。我不知道为什么它会不一致。我仍在等待 OP 解释不一致之处。 :)

标签: prolog prolog-findall


【解决方案1】:

您的实现存在几个问题。

  1. 一开始没有清理。在T,之前添加retractall(temp(_))

  2. obtain/2 将获得许多不同的答案,因为retract(temp(A)) 将给出许多答案,并且因为第二个子句obtain(S,S) 将始终是一个解决方案。这可以通过在retract 之后添加剪辑来保存。

    | ?- 获得([],S)。 S = [2,1] ? ; S = [1] ? ; S = [2] ? ; S = [] ? ; 不
  3. 您可能想要更改顺序,方法是使用asserta/1 或重新定义obtain/2

  4. 您的定义不可重入。这不能轻易解决。您将需要一些类似gensym 的功能或一些更高级的功能。

  5. 有关assert/1assertz/1 的详细说明,请参阅this answer

【讨论】:

    【解决方案2】:

    试试这个,我们在retract/1 和显式assertz/1 之后删减(!):

    solutions(A,T,_) :- 
       T,
       assertz(temp(A)),
       fail.
    solutions(_,_,S) :-
       obtain(S).
    
    obtain([A|S]) :-
       retract(temp(A)), !,
       obtain(S).
    obtain([]).
    

    工作正常,但不可重入,第二次查询结果错误:

    ?- solutions(X,between(1,3,X),L).
    L = [1, 2, 3].
    
    ?- solutions(X-R,(between(1,3,X),solutions(Y,between(1,X,Y),R)),L).
    L = [3-[2-[1-[1], 1, 2], 1, 2, 3]].
    

    编辑 08.11.2020:
    这是使用 gensym/2 的可重入解决方案:

    solutions(A,T,L) :-
       setup_call_cleanup(
          gensym('bag',B),
          solutions(B,A,T,L),
          retractall(temp(B,_))).
    
    solutions(B,A,T,_) :- 
       T,
       assertz(temp(B,A)),
       fail.
    solutions(B,_,_,S) :-
       obtain(B,S).
    
    obtain(B,[A|S]) :-
       retract(temp(B,A)), !,
       obtain(B,S).
    obtain(_,[]).
    

    现在两个查询都可以正常工作:

    ?- solutions(X,between(1,3,X),L).
    L = [1, 2, 3].
    
    ?- solutions(X-R,(between(1,3,X),solutions(Y,between(1,X,Y),R)),L).
    L = [1-[1], 2-[1, 2], 3-[1, 2, 3]].
    

    警告:具有逻辑更新语义的 Prolog 系统
    在反复收回/1期间可能效率低下。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-08
      • 2012-01-25
      • 2015-08-05
      • 2011-01-01
      • 2011-10-24
      • 2011-05-31
      相关资源
      最近更新 更多