嘿,我正在尝试创建一个谓词,用于在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].
谢谢你的帮助。
表示数据的方式被称为defaulty,因为在推理时需要默认情况:
- 这是一份清单吗&右箭头;某事成立
- 否则→其他的东西也适用
这样的表述是麻烦的根源。例如,考虑另一个答案中的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
有了这样的表示,我们可以象征性地区分这些情况。我将此作为一个更具声明性的解决方案的起点。
为了使事情尽可能简单,如果当前被检查的元素是否是列表,我们可以添加一个测试。如果它确实是一个列表,那么它的元素也应该反转。所以在代码中:
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)
).
此外,这并不重要,只是为了避免混淆,请注意我是如何将A
和R
分别用于Accumulator
和Result
的。在您的代码中,它们目前是交换的,这对我个人来说可能有点令人困惑,尤其是当谓词变得更长、更复杂时。
无论如何,让我们看看您提供的查询:
?- 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的回答,作为这个问题的后续内容。
问题的另一个解决方案是使用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].