我遇到了一个问题,我所提出的每个Prolog问题的答案最终都会被回复。这是因为我被告知如何使用累加器来反转列表,现在我似乎能够解决问题的唯一方法是使用类似的程序,它给出了答案,但也反转了列表。
例如,当被要求编写一个程序,用第三个参数替换第一个参数内的第二个参数的所有实例,并将结果列表作为它的第四个参数时,我编写了这段代码:
replace(L, A, B, X):-
accrep(L, [], A, B, X).
accrep([H | T], Y, A, B, X):-
H = A,
accrep(T, [B | Y], A, B, X).
accrep([H | T], Y, A, B, X):-
H \= A,
accrep(T, [H | Y], A, B, X).
accrep([], X, _, _, X).
这确实在技术上解决了问题,但也反转了没有被要求的列表,我怀疑当我向后提交正确的答案时,任何人都会留下深刻的印象。但是我想不出一种方法可以避免这种情况,并且在我不应该首先撤销它的代码中添加不反转列表的代码似乎很荒谬。
任何人都可以告诉我如何使用累加器而不会遇到这个问题吗?我和其他多个简单程序也有同样的问题。
谢谢, 亚历克斯。
答案 0 :(得分:2)
这是查看它的单向:当你有一个带累加器的递归(通常作为参数对实现)时,它通常看起来像这样:
generic(..., Final, Final, ...).
generic(..., Previous, Final, ...) :-
...
generic(..., Next, Final, ...).
递归条款
Previous
值Next
累加器值Final
累加器值从递归调用返回给调用者。这在实现计数器时最为明显,其中所有累加器参数都是整数。 Previous
是旧的计数器值,Next
是另一个,Total
是最终结果:
counter(..., Total, Total, ...).
counter(..., Previous, Total, ...) :-
...
Next is Previous+1,
counter(..., Next, Total, ...).
你所做的非常相似:你的每个累加器参数都是正确的列表:Previous
是你到目前为止构建的列表,Next
是{{ 1}}前面加了一个额外的元素,Previous
是最后的列表。
Final
到目前为止,这么好。现在,请记住,Prolog对数据结构的构建非常放松。您可以在其中留下空洞(以自由变量的形式),并在以后填充它们(通过实例化变量)。对于列表,这意味着您可以拥有一个包含未实例化尾部的列表,并在以后提供其余部分。将它与累加器的想法放在一起,让所有累加器参数为列表尾部:revlist(..., Final, Final, ...).
revlist(..., Previous, Final, ...) :-
...
Next = [New|Previous],
revlist(..., Next, Final, ...).
到目前为止列表的末尾,并通过实例化Previous
扩展列表到另一个列表元素。这会为您提供一个新的尾Previous
,您可以将其传递给递归。您会看到与前一个模式的唯一区别在于构造list元素的方式:
Next
成功时,此谓词的调用者将在第一个累加器参数中找到列表的开头,在第二个累加器参数中找到尾部。该列表与创建元素的顺序相同,可以通过将fwdlist(..., Final, Final, ...).
fwdlist(..., Previous, Final, ...) :-
...
Previous = [New|Next],
fwdlist(..., Next, Final, ...).
设置为Final
来终止。
注意:(1)可以消除最后一种情况下的[]
参数 - 我只是将其留在那里以显示对称性。 (2)这整个解释非常程序化,并且在输入/输出参数方面 - 实际上列表示例将以多种模式工作。
答案 1 :(得分:1)
我认为您使用累加器是因为您正在考虑采用程序解决方案。 简单地避免它,您的代码将更简单,并将解决问题。这是一个开始,请完成它。
replace(L, A, B, X):-
accrep(L, A, B, X).
accrep([], _, _, []).
accrep([A|R], A, B, [B|S]) :- accrep(R, A, B, S).
....