Prolog:反转列表中的每个第二个列表元素

时间:2011-05-14 17:55:13

标签: 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函数失败。 我还担心当原始列表最后只包含一个列表时会发生什么。

1 个答案:

答案 0 :(得分:0)

因为你说第二次迭代后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,因为那是第二个(和最后一个)等式的值

在你的程序中发生了同样的事情:

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

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

所以你怎么解决这个问题?看看你写[X,S | T]的方式来区分你想要处理的前两个元素。你只需对结果做同样的事情:
写它像[XResult,SResult | Rest] 当然,XResult将只是X而SResult将与S(Rev)相反 休息将是你从doStuff / 2的递归调用得到的东西

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

您可以查看有关listsrecursion

的内容