Prolog-递归追加到列表返回false

时间:2020-09-27 18:42:54

标签: prolog

标题说明了一切,但我们又来了。尝试将其递归地添加到Prolog中的列表中,而我之前已经通过具有“临时缓冲区”(通过nb_setval / nb_getval)使其工作了,我想学习如何以一种稍微合适的方式来递归地附加到列表。

我已经了解到Prolog可以围绕绑定工作,一旦绑定了某些东西就很难操纵它,所以最初我还是坐在这里,但是我已经理解了为什么它不起作用:

recursiveAppend([], _).
recursiveAppend([H|T], Output):-
    append(H, [], Output),
    recursiveAppend(T, Output).

这使我更改了代码并转到以下内容:

recursiveAppend([], _).
recursiveAppend([H|T], Output):-
    append(H, Output, NewOutput),
    recursiveAppend(T, NewOutput).

我曾希望能行得通,因为这对我自己以及对其他人来说很有意义,同时也对其他StackOverflow问题进行了搜索。不幸的是,在SWI-Prolog中调用此谓词只会返回 false

?- recursiveAppend([1, 2, 3, 4, 5], L1). false

在这种情况下,预期/期望的结果将是:

?- recursiveAppend([1, 2, 3, 4, 5], L1). L1 = [1, 2, 3, 4, 5].

为澄清起见,如果“充实”,程序的运行时应如下所示:

recursiveAppend([H|T], Output):-
    % H is 1, Output is []
    append(H, Output, NewOutput),
    % NewOutput is [1]
    recursiveAppend(T, NewOutput).

recursiveAppend([H|T], Output):-
    % H is 2, Output is [1]
    append(H, Output, NewOutput),
    % NewOutput is [1, 2]
    recursiveAppend(T, NewOutput).

recursiveAppend([H|T], Output):-
    % H is 3, Output is [1, 2]
    append(H, Output, NewOutput),
    % NewOutput is [1, 2, 3]
    recursiveAppend(T, NewOutput).

recursiveAppend([H|T], Output):-
    % H is 4, Output is [1, 2, 3]
    append(H, Output, NewOutput),
    % NewOutput is [1, 2, 3, 4]
    recursiveAppend(T, NewOutput).

recursiveAppend([H|T], Output):-
    % H is 5, Output is [1, 2, 3, 4]
    append(H, Output, NewOutput),
    % NewOutput is [1, 2, 3, 4, 5]
    recursiveAppend(T, NewOutput).

recursiveAppend([], _). % First argument (list) is empty, and the second argument (list) has been populated (with [1, 2, 3, 4, 5]), program done.

即使这个问题可能已经被问过一百万遍了,任何帮助都值得赞赏!

2 个答案:

答案 0 :(得分:3)

在Prolog中,“递归追加”通常不是很有意义。该问题应包含有关您要解决的问题的信息。目前还不是这个。这与您如何尝试解决问题有关。 “如何”是“递归追加”,但是几乎可以肯定,这不是您应该如何真正解决该问题的方法。如果我们知道问题是什么,而不是您想解决的方式,我们可以提供更好的帮助。

以问题中的示例为例,以https://stackoverflow.com/a/64092447/4391743中的解决方案为例:

?- recursiveAppend([1, 2, 3], Ys).
Ys = [1, 2, 3].

?- recursiveAppend(Xs, [1, 2, 3]).
Xs = [1, 2, 3] ;
% nontermination after first answer

?- recursiveAppend([1, 2, X], [A, B, 3]).
X = 3,
A = 1,
B = 2.

?- recursiveAppend([1, 2 | Rest], [A, B, 3, 4]).
Rest = [3, 4],
A = 1,
B = 2 ;
% nontermination after first answer

如果这是您想要的,那么您似乎想要的是“列表副本”谓词。这是更短,更快,更完整的一个:

list_copy([], []).
list_copy([X | Xs], [X | Ys]) :-
    list_copy(Xs, Ys).

没有上面谓词所具有的非终止性问题:

?- list_copy([1, 2, 3], Ys).
Ys = [1, 2, 3].

?- list_copy(Xs, [1, 2, 3]).
Xs = [1, 2, 3].

?- list_copy([1, 2, X], [A, B, 3]).
X = 3,
A = 1,
B = 2.

?- list_copy([1, 2 | Rest], [A, B, 3, 4]).
Rest = [3, 4],
A = 1,
B = 2.

如果参数之一是列表,另一个参数是变量,则会建立一个新的列表结构并将其绑定到该变量。

但是...为什么您根本需要一个新的列表结构?在纯Prolog中,您无法分辨两个术语是相同(即共享相同的内存位置)还是结构上“相等”。您通常都不在乎(或应该)。 (在非纯Prolog中,有一些用于共享和显式复制的知识,但同样,我们也不知道您要做什么。)

因此,如果我们无法确定“副本”确实是副本还是“相等条件”,那么我们根本不需要复制。只需统一即可获得与上述完全相同的行为:

?- [1, 2, 3] = Ys.
Ys = [1, 2, 3].

?- Xs = [1, 2, 3].
Xs = [1, 2, 3].

?- [1, 2, X] = [A, B, 3].
X = 3,
A = 1,
B = 2.

?- [1, 2 | Rest] = [A, B, 3, 4].
Rest = [3, 4],
A = 1,
B = 2.

无需复制,当然也不需要“递归追加”即可实现统一,Prolog知道如何为您实现统一。

如果这不是您想要的,请告诉我们实际的问题是什么。几乎肯定不是“递归追加”。

答案 1 :(得分:1)

Prolog是一种不同的编程范例。它要求您“忘记”所有有关编程的知识,并虚心学习。在使用“普通”变量并影响不同的值时,不要尝试学习Prolog,Prolog变量只有一个值或没有值。它们可能仅在回溯时才采用不同的值,并尝试为程序中的所有变量找到满足所有给定谓词的另一组值。

建议您阅读“立即学习Prolog”之类的书籍。互联网上免费提供来自州立大学的大量教程。

基于您的最新编辑,给出了调用recursiveAppend的示例,这是与该示例一致的代码。

recursiveAppend(X, Y) :- recursiveAppend(X, [], Y).

    recursiveAppend([], X, X).
    recursiveAppend([H|T], Current, Output):-
        append(Current, [H], NewTemp),
        recursiveAppend(T, NewTemp, Output).

您的早期代码返回false,因为append将列表作为参数。因此,附加整数(输入列表的项目)将始终失败。我创建了一个版本recursiveAppend / 3来在第二个arg中累积当前列表。在列表的末尾,当前列表成为最终输出。您能否通过更多示例进一步测试它,并告诉我们它是否按要求工作?