Prolog:反转列表中每隔一秒的列表元素



我必须编写一个程序,该程序将获取列表中的列表,并且应该每隔一个列表反转一次,然后返回结果。像这样:

doStuff([[1,2], [3,4], [5,6], [7,8]], R).
R = [[1,2], [4,3], [5,6], [8,7]]

这是我到目前为止所拥有的:

doStuff([],_).
doStuff([X,S|T],R):- reverse(S,Rev), add(X,Rev,R), doStuff(T,R).
doStuff([X|[]], R):- add(X,R,R).
reverse([X|Y],Z,W) :- reverse(Y,[X|Z],W).
reverse([],X,X).
add(X,[],X).
add(X,L,[X,L]).

我的问题是,在第二次迭代中,add函数失败了。我还担心当原始列表末尾仅包含一个列表时会发生什么。

既然你说 add/3 在第二次迭代后失败,我假设你使用了 trace/0
无论如何,这里是:

[trace]  ?- doStuff([[1,2], [3,4], [5,6], [7,8]], R).
   Call: (6) doStuff([[1, 2], [3, 4], [5, 6], [7, 8]], _G405) ? creep
   Call: (7) lists:reverse([3, 4], _G496) ? creep
   Exit: (7) lists:reverse([3, 4], [4, 3]) ? creep
   Call: (7) add([1, 2], [4, 3], _G405) ? creep
   Exit: (7) add([1, 2], [4, 3], [[1, 2], [4, 3]]) ? creep
   Call: (7) doStuff([[5, 6], [7, 8]], [[1, 2], [4, 3]]) ? creep
   Call: (8) lists:reverse([7, 8], _G514) ? creep
   Exit: (8) lists:reverse([7, 8], [8, 7]) ? creep
   Call: (8) add([5, 6], [8, 7], [[1, 2], [4, 3]]) ? creep
   Fail: (8) add([5, 6], [8, 7], [[1, 2], [4, 3]]) ? creep
   Redo: (7) doStuff([[5, 6], [7, 8]], [[1, 2], [4, 3]]) ? creep
   Fail: (7) doStuff([[5, 6], [7, 8]], [[1, 2], [4, 3]]) ? creep
   Redo: (6) doStuff([[1, 2], [3, 4], [5, 6], [7, 8]], _G405) ? creep
   Fail: (6) doStuff([[1, 2], [3, 4], [5, 6], [7, 8]], _G405) ? creep
false.

那么为什么它会失败呢?这是因为Prolog的主要特征之一。基本上,Prolog中的一个变量,一旦它取了一个值,它就永远不会改变如果您到目前为止使用命令式语言,这听起来可能有点奇怪,但考虑到数学中会发生完全相同的事情。
例如,请考虑以下等式:

x+3=4  
4-x=5

从第一个我们得到 x=1
从那一秒开始,我们得到 x=-1
由于 x 不能是 1 和 -1,我们说没有 x 来满足上述方程;
并不是说 x 是 -1,因为这是第二个(也是最后一个)方程的值

在 Yout 程序中会发生完全相同的事情:

doStuff([X,S|T],R):- reverse(S,Rev), add(X,Rev,R), doStuff(T,R).

所以第一次给 R 赋值时,doStuff/2 被调用 R 的值。
显然,这不是正确的值,所以 doStuff/2 失败

那么如何解决这个问题呢? 看看你写[X,S|T] 分隔要处理的前两个元素。您只需对结果执行完全相同的操作:
写成[X,SResult|休息]当然,XResult 将是简单的 X,而 SResult 将是 S (Rev) 的反面。
休息将是你从doStuff/2的递归调用中得到的

最后但并非最不重要的一点是,您应该检查最终调用的子句。

你可以检查一些关于列表和递归的东西

最新更新