PROLOG的深度逆转 - 列表

时间:2016-07-28 06:24:58

标签: prolog nested-lists declarative-programming

嘿,我正在尝试为PROLOG中的嵌套列表生成深度反转创建谓词。

目前我得到了这个谓词

reverse(L,A) :- rev(L,[], A).
rev([],A,A).
rev([H|L],R,A) :- rev(L,[H|R],A).

结果如下:

reverse([1,2,3],A).
A = [3, 2, 1].

reverse([[0,1],2,3],A).
A = [3, 2, [0, 1]].

问题是,内部列表没有反转。它应该是这样的:

reverse([[0,1],2,3],A).
A = [3, 2, [1, 0]].

reverse([1,2,[3,4,5,[6,7],8],[9,10],11,12],A).
A = [12,11,[10,9],[8,[7,6],5,4,3],2,1].

感谢您的帮助。

3 个答案:

答案 0 :(得分:3)

您表示数据的方式称为默认,因为在推理时需要默认案例:

  • 是一个清单吗? →有些东西
  • 否则→还有别的东西。

这种表现形式是一个丰富的麻烦来源。例如,从另一个答案中考虑my_reverse/2。它的主要问题是过早地错误地 提交到其中一个案例,尽管两个案例仍然可能:

?- my_reverse([X], Ls).
Ls = [X].

但这个答案仅适用于X 列表的情况!此问题导致谓词的以下奇怪行为:

?- my_reverse([X], Ls), X = [1,2,3].
Ls = [[1, 2, 3]],
X = [1, 2, 3].

这意味着即使X是一个列表,其元素反转!

你应该始终以更清晰的表现形式来区分可能出现的情况。

例如,您对以下表示数据的方式有什么看法:

  • list(Ls)代表列表 Ls
  • n(N)代表数字 N

通过这样的表示,我们可以象征性地区分这些案例。我将此作为更具声明性的解决方案的起点。

答案 1 :(得分:1)

为了使事情尽可能简单,如果要检查的当前元素是否为列表,我们可以添加测试。如果它确实是一个列表,那么它的元素也应该反转。所以在代码中:

my_reverse(L,R) :- rev(L,[],R).

rev([],A,A).
rev([H|T],A,R) :-
    ( is_list(H) ->        % If H is a list
      rev(H,[],X),         %   then reverse H as well
      rev(T,[X|A],R)
    ;
      rev(T,[H|A],R)
    ).

此外,并非真正重要,只是为了避免混淆,请注意我分别使用AR分别用于AccumulatorResult。在你的代码中,它们目前是交换的,这对我个人来说可能有点令人困惑,特别是当谓词变得越来越复杂时。

无论如何,让我们来看看你提供的查询:

?- my_reverse([[0,1],2,3],R).
R = [3, 2, [1, 0]].

?- my_reverse([1,2,[3,4,5,[6,7],8],[9,10],11,12],R).
R = [12, 11, [10, 9], [8, [7, 6], 5, 4, 3], 2, 1].

以及一些一般性问题:

?- my_reverse(L,R).
L = R, R = [] ;
L = R, R = [_G2437] ;
L = [_G2437, _G2443],
R = [_G2443, _G2437] ;
L = [_G2437, _G2443, _G2449],
R = [_G2449, _G2443, _G2437] ;
L = [_G2437, _G2443, _G2449, _G2455],
R = [_G2455, _G2449, _G2443, _G2437] 
...

?- my_reverse([[X,Y]|T],R), member(a,T), length(X,2).
X = [_G2588, _G2591],
T = [a],
R = [a, [Y, [_G2588, _G2591]]]
;
X = [_G2594, _G2597],
T = [a, _G2588],
R = [_G2588, a, [Y, [_G2594, _G2597]]]
;
X = [_G2594, _G2597],
T = [_G2582, a],
R = [a, _G2582, [Y, [_G2594, _G2597]]]
...

但请注意,使用此谓词后,在找到查询的第一个答案后不会发生终止:

?- my_reverse(X,[X]).
X = [X] ;
...

但由于这不是OP问题的要求/要求,我认为它没问题。

修改

请阅读@mat's answer作为此问题的后续内容。

答案 2 :(得分:0)

针对您的问题的另一个解决方案是使用cut和内置谓词“is_list / 1”来检查当前调用中是处理简单术语还是列表。 这是代码:

deepReverse(List,R):-deepReverseTail(List,[],R).

deepReverseTail([],Acc,Acc).

deepReverseTail([H|T],Acc,R):-             % when H is a list
     is_list(H),                           % check if it's a list.
     !,                                    % cut the process if not. 
     deepReverseTail(H,[],Hrev),           % reverse this current list
     deepReverseTail(T,[Hrev|Acc],R).      % continue the general recursion

deepReverseTail([H|T],Acc,R):- deepReverseTail(T,[H|Acc],R). % when H is a simple term

第三行中的“cut”确保您只处理此定义中的列表,而处理简单术语将在下一个定义中。

输出示例:

7 ?- deepReverse([a,[d,f],[],[[k],g]],R)
R = [[g, [k]], [], [f, d], a].