我正在尝试在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).
然而,这给了我不一致的结果。怎么了?提前谢谢。
答案 0 :(得分:2)
您的实施存在一些问题。
一开始没有清理。在retractall(temp(_))
T,
obtain/2
会有很多不同的答案,因为retract(temp(A))
会给出很多答案,因为第二个句子obtain(S,S)
将始终是一个解决方案。这可以通过在retract
之后添加剪辑来保存。
| ?- obtain([],S). S = [2,1] ? ; S = [1] ? ; S = [2] ? ; S = [] ? ; no
您可能希望使用asserta/1
或重新定义obtain/2
来更改订单。
您的定义不可重复。这无法轻易解决。您需要一些gensym
类功能或一些更高级的功能。
要获得assert/1
与assertz/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期间效率低下。