了解prolog中反向列表的这种实现

时间:2016-09-26 11:07:18

标签: prolog

我已经编写了以下用于撤销给定列表的小知识库,

reverse_list([],[]).
reverse_list([X|L1], [L2|X]) :-
   reverse_list(L1, L2).

目前,执行时

reverse_list([a,b,c,d], X).

它产生,

X = [[[[[]|d]|c]|b]|a].

对其发生原因的解释将非常感激。而且,我该如何解决这个问题呢?

我认为在最后一步L2成为[]并且在反向传播期间它变得像那样。 如何使用此方法的修改获得类似X = [d,c,b,a]的输出。

P.S:我是Prolog的新人。

3 个答案:

答案 0 :(得分:5)

您可以推理代数关于Prolog程序。

为了向您展示一种方式,让我们考虑一个更简单的目标,该目标也会显示问题:

?- reverse_list([a], Ls).
Ls = [[]|a].

为什么这样做?

因为,如果以下,

?- [a] = [X|L1], Ls = [L2|X], reverse_list(L1, L2).
L1 = L2, L2 = [],
Ls = [[]|a],
X = a.

我只是插入reverse_list/2的定义,使等效与原始查询相关,因此当然仍然显示问题。

现在重点:我们可以概括查询(只是省略一些目标),仍然看到问题:

?- [a] = [X|L1], Ls = [L2|X].
L1 = [],
Ls = [L2|a],
X = a.

很明显子句头包含错误:您正在描述[Ls|a]形式的术语。这是不是列表,因为a atom

+1以获得良好的命名约定! list_reversed/2会更好(避免强制要求其他使用模式也有意义),并且可能会有更好的名称。

答案 1 :(得分:5)

您发现您的程序存在问题,而@mat向您展示了为什么给出的答案不正确。这是另一种本地化问题的方法:简单地坚持你的期望!在您的情况下,这将是:

?- reverse_list([a,b,c,d], [d,c,b,a]).
false.  % unexpected failure

所以在这里你说这应该是这种情况,但事实并非如此。因此,您的程序太专业于查询。它缺乏这种解决方案。

要在程序中找到负责任的部分,您现在可以概括您的程序以使目标仍然失败

:- op(950, fy, *). % prefix *, see this for more.
*(_).

reverse_list([],_/*[]*/).
reverse_list([X|L1], [L2|X]) :-
   * reverse_list(L1, L2).

所以我已经删除了规则中的目标和事实中的第二个参数 - 但程序仍然失败了!您现在需要修改剩余可见部分中的某些内容以解决问题。

reverse_list([X|L1], [L2|X])
              ^          ^

X作为元素和列表出现一次。

有一个简单的约定可以避免此类错误:名称列表最好添加复数 - s。因此,如果您有一个元素X,请调用列表Xs,这将是[X|Xs]。通过这种方式,问题将更容易发现:

  reverse_list([X|Xs], [Ys|X]) :- ...
                           ^ suspicious!

答案 2 :(得分:4)

要反转列表,您需要三个参数:

reverse_list(L,L1):-reverse_list(L,[],L1).
reverse_list([],ACC,ACC).
reverse_list([X|L], ACC,L1):- reverse_list(L,[X|ACC],L1).

首先调用reverse_list(L,L1)调用reverse_list(L,[],L1).,其中第二个参数用作累加器,以与第一个列表相反的顺序存储所有元素。 所以它调用reverse_list([X|L1], ACC,L).,在第一次调用ACC(累加器)是空列表,然后你递归调用reverse_list(L1,[X|ACC],L).这是同样的事情,但你从第一个列表移动X并存储到累加器。 最后,当第一个列表为空并且所有元素以相反顺序传递给ACC时,该过程停止,然后您将第三个列表与ACC统一。

举个例子: L=[1,2,3],ACC=[],L未被评估。 致电reverse_list([2,3],[1],L). 在下一个递归步骤中调用reverse_list([3],[2,1],L)。 致电reverse_list([],[3,2,1],[3,2,1]).最后一个列表与ACC=[3,2,1]统一。

查询上面的例子给出:

?- reverse_list([1,2,3],L).
L = [3, 2, 1].