【问题标题】:Prolog reverse/2 list output formatProlog reverse/2 列表输出格式
【发布时间】:2025-12-01 12:20:03
【问题描述】:

我是 Prolog 的初学者,我被困在家庭作业中。我必须建立一个谓词myReverse(XS,YS),其中XSYS 的反向列表。我已经建立了一些逻辑如下:

myReverse([],[]).
myReverse([H],[H]).
myReverse([L|H],[H|T]) :- myReverse(L,T).

这有点工作,但输出不是我想要的。一些例子:

myReverse(L,[]).
L = []                  % ok, that's fine

myReverse(L,[a]).
L = [a]                 % still fine

myReverse(L,[a,b]).
L = [[b]|a]             % expected [b,a]

myReverse(L,[a,b,c]).
L = [[[c]|b]|a]         % expected [c,b,a]

...

有没有什么方法可以在不使用累加器或第三方实现(如 appendappend)的情况下实现预期的输出?

编辑:这个问题NOTReversing a List in Prolog 重复,因为我确实想使用累加器。此外,这个问题更多的是关于我给定解决方案的输出格式,而不是解决方案本身。

【问题讨论】:

  • 请检查我的答案。
  • 您在问“如何在 Prolog 中实现reverse/2”,就好像您无法使用谷歌(或其他搜索引擎)甚至教科书找到解决方案。您显然问“我的方法怎么错了”。这种问题往往会引起负面反馈,这反过来可能会让你相信 * 是一个愚蠢的地方,粗鲁的无所不知的人会滥用初学者。
  • @DanielLyons 这个问题不是“Reversing a List in Prolog”的重复,因为我在这里提问之前显然做了一些非常深入的研究。在那个问题中,赞成的答案建议使用累加器,正如我的问题中所说,我显然不想这样做。
  • “一些非常深入的研究”是的。我用“prolog reverse without accumulator”进行了谷歌搜索,不到 3 分钟就找到了 * 问题和答案。您谈论“输出格式”,但实际上,您的尝试中错误的不是格式,而是它不是一个反向列表,它是某种嵌套结构。这绝对不是一个颠倒的清单。这里真正有趣的问题是,“在没有累加器的情况下,在 Prolog 中反转列表意味着什么”,为此,您可能需要了解列表是什么,等等。

标签: prolog


【解决方案1】:

您误解了[H|T] 表示法,通过示例reverse(L, [a, b]) 会发现它。

第一次统一:

rule: myReverse([L|H],[H|T]) :- myReverse(L,T).
unified: myReverse([L|a], [a|[b]]) :- myReverse(L, [b]).

此时a 是单个原子,而不是列表,T in [H|T] 需要是列表才能完成列表。 [a, b, c].(a, .(b, .(c, []))) 的语法糖。

你的第二个统一,第三个统一是:

second: myReverse([b], [b]).
going back: myReverse([[b]|a], [a|[b]]) :- myReverse([b], [b]).
which outputs as: myReverse([[b]|a], [a, b]).

您的输出[[b]|a] 不是一个完整的列表,因为a 是一个原子,而不是一个列表,这就是为什么它不是输出为[[b], a]

要不使用累加器,您需要在退出递归并返回堆栈帧时将元素添加到列表中,记住在处理列表或原子时:

myReverse([], []). % base case
myReverse([Head|Tail], Reversed) :-
    myReverse(Tail, TailReversed), % recursive call
    add_to_tail(Head, TailReversed, Reversed). % Put Head onto the end

add_to_tail(X, [],[X]). % base case
add_to_tail(X, [H|T], [H|Out]) :- 
    add_to_tail(X, T, Out). % recursive call, work done on exit

使用累加器效率更高。祝你学习 Prolog 好运。

【讨论】: