我有一个 Prolog 规划器,它的工作正常,但有一个主要问题是每次只能生成一个计划。虽然计划是正确的,但我的应用确实需要所有可能的计划。
plan(State, Goal, _, Moves) :- subsetB(Goal,State), write('moves are'), nl, reverse_print_stack(Moves).plan(State, Goal, Been_list, Moves) :- effects(Name, [Preconditions, Add,Delete]), //a list of of rules governing the domain conditions_met(Preconditions, State), //checks if all preconditions are present in the state change_state(State, Add,Delete, Child_state), //add predicates from Add list, removes predicates in the Delete list and stores result in Child_state \+(member_state(Child_state, Been_list)), //checks if Child_state hasn't been previously visited stack(Child_state, Been_list, New_been_list), stack(Name, Moves, New_moves), plan(Child_state, Goal, New_been_list, New_moves).change_state(S, [],[], S).change_state(S, [], Delete, S_new) :- change_state(S, [],[], S2), apply_del(Delete, S2, S_new).change_state(S, Add,Delete, S_new) :- change_state(S, [], Delete, S2), apply_add(Add, S2, S_new).apply_add([],State,State).apply_add([activate(App)|Rest],State,InterimState) :-apply_add(Rest,State,S2),find_stones(App,State,StonesToBeActivated), make_active(StonesToBeActivated,S2, InterimState).apply_add([First|Rest],State,InterimState) :- apply_add(Rest,State,S2),add_element(First, S2, InterimState).apply_del([],InterimState,InterimState).apply_del([First|Rest],InterimState,NewState) :- apply_del(Rest, InterimState,S2),del_element(First, S2, NewState).subsetB([],_).subsetB([F|R],S) :- member(F,S),subsetB(R,S).%dropping a stone inside app1 effects(drop(X,app1), %action [[stone(X),active(X)], %preconditions [in(app1,X)], %postconditions : add list [active(X)]]). %postconditions : delete listgo(S,G,AllPlans):- findall(Moves, plan(S,G,[S],Moves),AllMoves).conditions_met(P, S) :- subsetB(P, S).
示例调用 go([in(app1,s1), stone(s2), active(s2),stone(s3),active(s3)],[in(app1,s1),in(app1,s3),in(app1,s2)],AllPlans).
回答:
drop(s2,app1)drop(s3,app1) //correct_2368_2366_2364_2362_2360_2358_2356_2354_2352_2350_2348_2346_2344_2342_2340_2338_2336等… 无限
回答:
要查找目标的所有解决方案,请查看bagof 或 findall。还是我遗漏了什么?
像这样:
?- findall(Moves, plan(State, Goal, _, Moves), AllMoves).
这些谓词的整个理念是,你指定要收集哪些参数,并得到该谓词下所有可能的实例化列表。从这个意义上讲,你通常有一个“返回”值(一个与结果一起实例化的参数),然后你可以查看或打印它,而不是在查找解决方案的谓词中显式地打印它。
一个简单的例子:
foo(1). foo(2). foo(3). foo(4). foo(5). foo(6).bar(R) :- foo(A), A mod 2 =:= 0.findall(R, bar(R), Even).
现在谈谈递归:它是如何工作的?你不能在同一个谓词的不同子句之间共享变量。例如,这是不正确的:
baz(0, B).baz(X, B) :- X0 is X - 1, B1 is B + 1, baz(X0, B1).
因为在 baz
的第一个子句中 B 是一个单例变量。相反,你可以这样做:
baz(0, B, B).baz(X, B, Result) :- X0 is X - 1, B1 is B + 1, baz(X0, B1, Result).
现在你可以这样调用:
?- baz(10, 2, Result).Result = 12
但在第一个答案之后你仍然会遇到问题。
你得到单个正确的计划可能是因为 plan
的第一个子句不满足 subsetB
的要求,你进入了第二个子句。在那里,你创建了一个 Moves,它的尾部有一个自由变量,但这还不是问题。然而,问题是,当你找到你的第一个解决方案(都在第二个 plan
子句中,递归地),Moves 现在被绑定到一个动作列表,而不是开始寻找新的解决方案,你通过回溯再次进入第二个子句,带有已经填充的 Moves,这可能会搞乱算法的其余部分。
为了使其正确,你可能需要确保当你的 plan
回溯时,它开始寻找新的解决方案,并使用一个干净的 Moves。你可以从将 Moves 实例化为一个空列表并在累加器中收集结果开始,如上面的简单 baz
谓词所示。