copyList([], []). % base case
copyList([H|T], [H|R]) :-
copyList(T, R).
我"有点"了解递归是如何工作的,但是当我分析这个函数时,我真的很困惑。有人可以请一步一步解释这个函数中发生的事情以及如何使用下面的例子到达终点:
?- copyList([1,2,3],L).
答案 0 :(得分:2)
要了解会发生什么,您必须将Prolog视为定理解算器:当您向Prolog提供查询?- copyList([1, 2, 3], L).
时,您实际上是要求Prolog证明copyList([1, 2, 3], L)
是真的。
copyList([], []).
copyList([H|T], [H|R]):-
copyList(T, R).
因为它是第一次遇到,所以Prolog将尝试使用copyList([1, 2, 3], L)
一词来证明copyList([], [])
是真的。
要这样做,并且由于该子句没有正文(:-
之后没有),它只需要将查询的参数与子句的参数统一起来(统一[1, 2, 3]
和{ {1}}和[]
与L
)。虽然很容易将[]
与L5
统一(统一[]
),但无法将L5 = []
与[1, 2, 3]
统一起来。因此,Prolog无法通过使用第一个条款来证明您的查询。然后必须尝试使用第二个。
再一次,它将使用子句参数统一查询参数,以查看该子句是否适用:这里可以使用统一[]
来实现。现在必须查看H = 1, T = [2, 3], L = [H|R]
之后列出的条件是否得到尊重,因此必须证明:-
。完全相同的事情发生两次,直到它发现自己试图证明copyList(T, R)
。在那里,第一个条款适用,其工作已经结束。
您可以使用绘图总结执行,如下所示:
copyList([], R)
现在执行已经结束,我们可以通过跟随统一链看到原始copyList([1, 2, 3], L).
|
| try to use clause number 1, doesn't unify with arguments.
| use clause number 2 and L = [1|R]
|
` copyList([2, 3], R).
|
| try to use clause number 1, doesn't unify with arguments.
| use clause number 2 and R = [2|R2]
|
` copyList([3], R2).
|
| try to use clause number 1, doesn't unify with arguments.
| use clause number 2 and R2 = [3|R3]
|
` copyList([], R3).
|
| use clause number 1 and R3 = []. One solution found
| try to use clause number 2, doesn't unify with arguments.
| No more possibilities to explore, execution over.
是什么:
L
感谢Will Ness了解original idea如何解释变量的最终价值。
答案 1 :(得分:1)
虽然您的具体问题已经得到解答,但很少有评论。
首先,你也可以打电话给?- copyList(L,[1,2,3]).
或?- copyList([1,2,3],[1,2|Z]).
等。重要的是两个列表 的长度相等,以及它们的元素在相应的位置可以相等(统一),因为谓词的含义是它的两个参数列表是相同的 - 即长度相同,并且具有相同的元素。
例如,可以通过调用
违反第一个条件?- copyList(X, [A|X]).
因为它说第二个参数比第一个参数长一个元素。当然这样的解决方案不可能,但查询永远不会终止,因为第一个条款永远不会匹配,第二个条款永远都会匹配。