我试着理解这段代码是如何工作的但是我失败了。 它连接两个列表然后它反转结果。
reverse(L, RL):- reverse(L, [], RL).
reverse([], RL, RL).
reverse([H|T], S, RL):- reverse(T, [H|S], RL).
concat([], L, L).
concat([H|T1], L2, [H|T]):- concat(T1, L2, T).
concat_reverse(L1,L2,L):-concat(L1,L2,LN),reverse(LN,L)
我的老师告诉我进入调试模式并跟踪查询以了解但它没有帮助。
这是一个例子
5 ?- trace,concat_reverse([1,3],[4,5],S).
Call: (7) concat_reverse([1, 3], [4, 5], _G1444) ? creep
Call: (8) concat([1, 3], [4, 5], _G1569) ? creep
Call: (9) concat([3], [4, 5], _G1564) ? creep
Call: (10) concat([], [4, 5], _G1567) ? creep
Exit: (10) concat([], [4, 5], [4, 5]) ? creep
Exit: (9) concat([3], [4, 5], [3, 4, 5]) ? creep
Exit: (8) concat([1, 3], [4, 5], [1, 3, 4, 5]) ? creep
Call: (8) reverse([1, 3, 4, 5], _G1444) ? creep
Call: (9) reverse([1, 3, 4, 5], [], _G1444) ? creep
Call: (10) reverse([3, 4, 5], [1], _G1444) ? creep
Call: (11) reverse([4, 5], [3, 1], _G1444) ? creep
Call: (12) reverse([5], [4, 3, 1], _G1444) ? creep
Call: (13) reverse([], [5, 4, 3, 1], _G1444) ? creep
Exit: (13) reverse([], [5, 4, 3, 1], [5, 4, 3, 1]) ? creep
Exit: (12) reverse([5], [4, 3, 1], [5, 4, 3, 1]) ? creep
Exit: (11) reverse([4, 5], [3, 1], [5, 4, 3, 1]) ? creep
Exit: (10) reverse([3, 4, 5], [1], [5, 4, 3, 1]) ? creep
Exit: (9) reverse([1, 3, 4, 5], [], [5, 4, 3, 1]) ? creep
Exit: (8) reverse([1, 3, 4, 5], [5, 4, 3, 1]) ? creep
Exit: (7) concat_reverse([1, 3], [4, 5], [5, 4, 3, 1]) ? creep
S = [5, 4, 3, 1].
答案 0 :(得分:3)
让我们一点一点地看一下。
您使用过:
concat_reverse([1,3],[4,5],S).
Prolog试图将此统一起来。
concat_reverse(L1,L2,L)
匹配。 L1
与[1,3]
统一,L2
与[4,5]
统一。所以我们看右边:
concat_reverse(L1,L2,L):-concat(L1,L2,LN),reverse(LN,L)
Prolog首先进行深度搜索统一,因此会再次使用统一concat(L1,L2,LN)
和L1
检查L2
。
让我们一起看看两个concat
:
concat([], L, L).
concat([H|T1], L2, [H|T]):- concat(T1, L2, T).
如果有帮助,可以将这种模式匹配视为逻辑上的直通。第一个将匹配一个空列表,一些东西,以及相同的东西。这实际上是Prolog所做的深度优先搜索的停止条件。
第二个匹配一个带有头部和尾部的列表,一些具有相同头部和可能不同尾部的列表。在这一点上,我们匹配这个因为统一的工作原理。没有什么重要的是第三个列表。在统一期间,我们将改变“没什么重要”的东西。现在,我们匹配,所以我们遍历下一个concat,传递第一个列表的尾部,第二个列表,另一个“没什么重要”。
在下一个级别,我们匹配相同的条件。我们再次这样做,我们达到了停止状态。我们没什么重要的是第二个清单。因此,我们尝试通过统一从深度优先搜索中爬回来。我们在搜索树中添加了我们上面第一个匹配列表的头部。这是统一的。我们又爬了起来。我们提前一层。这是统一的。您知道什么,我们能够统一第一个concat
匹配的concat_reverse
字词。
现在我们来看看reverse
匹配的concat_reverse
部分。这是堆栈跟踪中的Exit(8)/Call(8)
。我们再往下走,用这些进行深度优先搜索:
reverse(L, RL):- reverse(L, [], RL).
reverse([], RL, RL).
reverse([H|T], S, RL):- reverse(T, [H|S], RL).
嗯,只有一场比赛,一场有两个任期。但现在我们搜索reverse
的两个选项。我们的列表不是空的,所以我们不匹配第一个(再次,这将是我们的停止条件)。我们可以匹配第二个。
我要停止因为继续这不会增加任何新东西。基本上,prolog解释器的工作是匹配,统一和深度优先搜索之一。
希望你已经或者已经有过关于为什么prolog进行深度优先搜索以及为什么这意味着它无法完成反驳(以及你可以做什么作为程序员以防止无限深度搜索)的课程。
基本上,当您编写prolog代码时,您可以像使用归纳证明或递归函数一样编写它。从停止状态开始,然后根据停止条件处理一般情况。根据构图定义事物,例如concat_reverse
。
我认为你应该看一个更简单的例子来更好地理解统一。这个例子有不必要的复杂性(虽然这些复杂性总是可以帮助你在编写自己的家庭作业的prolog代码时)。尝试单独查看reverse
,不要concat
和concat_reverse
。
答案 1 :(得分:3)
免责声明:我不认识你的老师,所以也许你不得不这样做......
告诉你有很多困难,并问为什么代码没有读到:
concat_reverse(L1,L2,L):-reverse(L2,R,L),reverse(L1,[],R).
然后:
seq([]) --> []. seq([E|Es]) --> [E], seq(Es). iseq([]) --> []. iseq([E|Es]) --> iseq(Es), [E]. concat_reverse2(L1,L2,L) :- phrase( ( iseq(L2), iseq(L1) ), L).
通常,我不建议使用调试器来理解谓词。
答案 2 :(得分:0)
在阅读(或写作)Prolog时,我想讲一个小故事。
例如,在阅读concat_reverse时,我就是这样解释的: “L是L1和L2的concat_reverse,如果首先LN是L1和L2的串联,其次,L是LN的反转”。
当我阅读concat时,我说: “[]和L的连接是L.” “如果T1和L2的串联为T,则[H | T1]和L2的连续为[H | T]。”
基本上,解释应该以某种方式简化表达式。如果我要写“concat”,我会想“关于concat什么是微不足道的事实?将任何列表连接到空列表是最初的列表。那么[H | T]的一般情况怎么样?将L连接到这是M如果M的头是H而M的其余部分是T到L的串联。换句话说,如果M是[H | RM]并且concat(T,则concat([H | T],L)是M L)是RM。“
至于反向,故事有点复杂,因为没有简单的说“如果......,RL就是L的逆转”。但我们仍然可以提出一个故事。例如,如果L的相应后缀被反转,然后S被连接到结果,我们可以说“S是L的反向后缀(称为RL)。”
因此对于空后缀,我们有反向([],RL,RL) - 如果L的空后缀被反转并且RL被连接到它,则RL是RL的后缀。
在一般情况下,如果L的后缀是[H | T],那么只有当[H | S]也是RL的后缀时,RL的后缀才是S.
这有点令人困惑,特别是当谓词被称为“反向”时。我们必须用一些想象力。但是,如果我们称它为:
concat_of_reversed_suffix_and_S([H|T], S, RL) :- concat_of_reversed_suffix_and_S(T, [H|S], RL).
这有点清楚 - [H | T]的反向是T的反向,后跟H.如果[H | T]是L的后缀而S是后缀或RL,那么T的反向其次是H,其次是S就是RL。我们用这种方式说这句长句:
reverse([H|T], S, RL) :- reverse(T, [H|S], RL).
调试器可以向您显示该过程,但最好让您的头脑中的故事解释它,然后您可以使用调试器进行确认。
在这种情况下,您可以看到:
Call: (10) reverse([3, 4, 5], [1], _G1444) ? creep
Call: (11) reverse([4, 5], [3, 1], _G1444) ? creep
[3,4,5]是L的后缀,[1]是RL的后缀。仅当[3,1]也是RL的后缀时才会出现这种情况,将[4,5]留作L的(较小的)后缀。
答案 3 :(得分:0)
concat_reverse(L1,L2,L) :-
concat_reverse(L1,L2,[],L).
concat_reverse([],[],L,L).
concat_reverse([],[B|R2],L3,L) :-
concat_reverse([],R2,[B|L3],L).
concat_reverse([A|R1],L2,L3,L) :-
concat_reverse(R1,L2,[A|L3],L).