findall的替代方案

时间:2015-03-23 18:39:08

标签: prolog prolog-findall

我正在尝试在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).

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

2 个答案:

答案 0 :(得分:2)

您的实施存在一些问题。

  1. 一开始没有清理。在retractall(temp(_))

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

    | ?- obtain([],S).
    S = [2,1] ? ;
    S = [1] ? ;
    S = [2] ? ;
    S = [] ? ;
    no
    

  4. 您可能希望使用asserta/1或重新定义obtain/2来更改订单。

  5. 您的定义不可重复。这无法轻易解决。您需要一些gensym类功能或一些更高级的功能。

  6. 要获得assert/1assertz/1的细则,请参阅this answer

答案 1 :(得分:0)

尝试一下,在缩回/ 1后显式断言(!),并明确断言z / 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期间效率低下。

相关问题