Prolog:递归无法正常工作
Posted
技术标签:
【中文标题】Prolog:递归无法正常工作【英文标题】:Prolog: recursion is not working properly 【发布时间】:2022-01-19 12:31:37 【问题描述】:我想写change_state(+L1, +L2, -L3).
L1 包含状态,例如:[碾磨、烧毁] L2 包含谓词,例如:[del(milled), add(shifted)] 而L3就是返回列表。
例子:
L1 = [milled, burned]
L2 = [del(burned), add(shifted)]
L3 = [milled, shifted]
所以 L1 是我的起始列表,根据 L2 中的谓词,我会更改 L1 的状态。
这是我的递归解决方案:
change_state([], [], []).
change_state(X, [], []).
change_state(State, [H|T], NewState) :-
functor(H, N, 1),
arg(1, H, A),
( N = del
-> remove_from_list(A, State, NewState)
; arg(1, H, A),
add_to_list(A, State, NewState) ),
print(NewState),
change_state(NewState, T, X),
print(NewState).
我还把一些打印到函数中进行调试。
现在的问题:
如果我用
调用函数change_state([milled, burned], [del(burned), add(lol), add(hi)], L).
我得到了结果
L = [milled].
所以只有 L2 中的第一个谓词有效。
但打印显示我:
[milled][lol,milled][hi,lol,milled][hi,lol,milled][lol,milled][milled].
所以它确实有效,但是由于递归,它回到了第一个状态。
知道如何解决这个问题吗?
【问题讨论】:
change_state(State, [H|T], NewState) :- ...
不应该是change_state(State, [H|T], X) :- ...
考虑到您的几乎尾递归调用change_state(NewState, T, X)
?
@RuudHelderman 刚刚尝试过,但现在我的退货清单是空的。
子句 change_state(X, [], []).
必须替换为 change_state(X, [], X)
。
结合你的两个答案有效!非常感谢!!
【参考方案1】:
虽然您的代码已经在 cmets 中指示的修改下正常工作,但我认为更清晰的实现如下:
change_state(State, Changes, NewState) :-
change_state_loop(Changes, State, NewState).
% Reverse the order of the first two arguments to avoid choice points.
change_state_loop([], State, State).
change_state_loop([Change|Changes], State, NewState) :-
do(Change, State, PartiallyUpdatedState),
change_state_loop(Changes, PartiallyUpdatedState, NewState).
% Use unification to choose the correct operation to perform.
do(del(Fluent), State, NewState) :- subtract(State, [Fluent], NewState).
do(add(Fluent), State, NewState) :- union(State, [Fluent], NewState).
【讨论】:
或者在foldl存在的情况下,change_state(State, Changes, NewState) :- foldl(do, Changes, State, NewState).
@RuudHelderman 不错!我真的很喜欢基于foldl/4
的解决方案。但是,我认为使用foldl/4
可以使代码更简洁,但不一定更清晰(当然对于初学者而言)。以上是关于Prolog:递归无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章