我正在尝试使用assertz()和retract()在SWI Prolog中编写广度优先搜索。但我遇到了一些问题,希望得到一些指导。我猜我正在做一些愚蠢的事情。
:- dynamic paths/1.
bfs_solve(Solution) :-
initial_state(Start),
assertz(paths([[Start]])),
breadthfirst(Solution).
breadthfirst([Node | Path]) :-
retract(paths([[Node | Path] | _])),
goal(Node).
breadthfirst(Solution) :-
retract(paths([Path | RestPaths])),
extend(Path, NewPaths),
conc(RestPaths, NewPaths, Paths1),
assertz(paths(Paths1)),
breadthfirst(Solution).
extend([Node | Path], NewPaths) :-
bagof([NewNode, Node | Path],
(s(Node, NewNode), \+ member(NewNode, [Node | Path])),
NewPaths),
!.
extend(Path, []).
initial_state([1, 2, 3, 4, 5]).
goal([0, 0, 0, 0, 0]).
% Function 's' is not detailed here as it is irrelevant to this problem
member(X, [X | Tail]).
member(X, [Head | Tail]) :-
member(X, Tail).
conc([], L, L).
conc([X | L1], L2, [X | L3]) :-
conc(L1, L2, L3).
问题是,一旦目标检查发生在
breadthfirst/1
中,它就会从数据库中撤回初始状态,因此当它到达 breadthfirst/1
的第二个定义时(调用 extend/2
函数的地方) ,没有什么可以收回,导致执行停止。
我在这里缺少什么?
谢谢!
如果您将对assert*和retract*的调用包装在几个实现队列的谓词中,您可能能够找出错误。排队需要什么?
(是不是也需要能推到前面,或者看上面而不弹出?)
我假设你想保持这个状态和全局? (为什么要使用数据库?)在这种情况下,您可以选择调用您的队列
queue/1
,然后:
:- dynamic queue/1.
empty_queue :-
retractall(queue(_)).
push_back(Back) :-
assertz(queue(Back)).
pop_front(Front) :-
once(queue(F0)), % first fact matched to a free variable
once(retract(queue(F0))), % retract exactly once the matched fact
Front = F0.
一个简单的测试,我压入[a,b,c],弹出两次,所以应该是'a',然后是'b',并打印队列的其余部分,应该是[c]:
?- empty_queue,
push_back(a),
push_back(b),
push_back(c),
pop_front(X0),
pop_front(X1),
forall(queue(A), format("~w~n", [A])).
c
X0 = a,
X1 = b.
(整个队列位于输出的第一行)
为了表明我们只弹出顶部:
?- empty_queue,
push_back(a),
push_back(b),
push_back(a),
pop_front(X),
forall(queue(A), format("~w~n", [A])).
b
a
X = a.
所以它似乎有效。