我试图了解this计划是如何运作的。
来自Daniel Lyons的代码'解决方案(来自上面的链接)takeout(X,[X|R],R).
takeout(X,[F |R],[F|S]) :- takeout(X,R,S).
perm([X|Y],Z) :- perm(Y,W), takeout(X,Z,W).
perm([],[]).
我尝试了解它如何使用此列表[1,2,3]
所以,我有perm([1,2,3],X).
一开始很容易理解,Y = [2,3]
然后Y = [3]
然后Y = []
之后调用perm([],[]).
,它会给我们W = []
现在,第一次调用takeout
- takeout(3, Z, []).
它返回Z = [3]
现在,我们回去了,perm([],[]).
给了我们W = [3]
,(因为此时Y是[3])
与上述相同,takeout(2, Z, [3])
和Z = [2, 3]
。
再次perm([], []).
和W = [2, 3]
。
takeout(1, Z, [2, 3])
,它首先给出了答案Z = [1, 2, 3]
在这里,我不知道为什么程序不会结束,递归完成,为什么takeout
和perm
再次有效?
之后takeout
被称为takeout(1, [2,3])
。
哪个适用于takeout(X,[F |R],[F|S])
,而不适用于takeout(X,[X|R],R).
,这是我的第二个问题,为什么?
答案 0 :(得分:1)
在Prolog中,谓词的行为与过程语言中的函数完全不同。调用函数来执行任务,执行,然后返回返回某些值或执行一些副作用,或两者兼而有之。
谓词定义了在其参数之间建立逻辑连接的关系和/或事实集。当对Prolog中的谓词进行查询时,Prolog将尝试查找参数变量的每个实例化,这将使该谓词成功(为真)。
在一个非常简单的案例中,我可能会有以下事实:
likes(tom, mary). % Tom likes Mary
likes(fred, mary). % Fred likes Mary
这里我有一个谓词或事实likes
,它定义了两个人之间的关系。我们称之为事实,因为它们都指定了与完全实例化的参数的精确,具体的关系。我可以进行查询以确定谁喜欢玛丽?,如下所示:
| ?- likes(Person, mary).
Person = tom ? ;
Person = fred
yes
查询首先返回Person = tom
,但表示一旦找到Person = tom
满足查询,就会有更多选项可供检查。输入;
告诉Prolog继续下一个解决方案(如果有的话),它会找到它:Person = fred
。
现在让我们考虑takeout/3
。这是一个谓词,它定义了一组变量之间的 relation 。
takeout(X,[X|R],R).
takeout(X,[F|R],[F|S]) :- takeout(X,R,S).
takeout/3
谓词为关系提供了两个谓词子句或规则。尝试阅读它们很有帮助:
R
是您从X
中取出[X|R]
后获得的。[F|S]
是您从X
中取出[F|R]
时获得的,如果 S
是您获取的X
R
} {} {}} {。}}。{/}
醇>
Prolog以分离的方式看待多个条款。也就是说,如果任何一个规则可以成立,则对谓词的查询或调用将成功。当对takeout/3
进行查询时,Prolog将在查询中查找给定变量的实例化,这将使其成立,并且它将尝试查找每个这样做的实例化。换句话说,如果满足条件的方法不止一种,它将回溯并尝试找到那些这样做的变量实例。
考虑查询:
?- takeout(X, [1,2,3], R).
Prolog能够通过实例化takeout(X, [X|R], R)
和takeout(1, [1,2,3], [2,3])
将其与第一个谓词子句X = 1
匹配为R = [2,3]
。因此,此查询将成功执行以下结果:
R = [2,3]
X = 1 ?
但是我们看到Prolog表明还有更多选择可供探索。那是因为还有另一个条款:takeout(X,[F|R],[F|S])
与查询takeout(X, [1,2,3], R)
匹配。因此Prolog 回溯并尝试第二个子句,匹配:
takeout(X, [1|[2,3]], [1|S]) :- % F = 1, R = [2,3]
takeout(X, [2,3], S).
Prolog将跟随递归调用takeout(X, [2,3], S)
并再次从第一个子句开始并尝试将takeout(X, [2,3], S)
与takeout(X, [X|R], R)
匹配,后者与{{{ 1}}和X = 2
(S = [3]
。递归展开或返回(就像在任何语言中一样),然后前一个调用头takeout(2, [2|[3]], [3]).
最终实例化为:{{1我们得到了:
takeout(X, [1|[2,3]], [1|S])
等等。类似行为适用于takeout(1, [1|[2,3]], [1|[3]])
。在查询R = [2,3]
X = 1 ? ;
R = [1,3] % that is, [1|[3]]
X = 2 ?
的上下文中,对perm
的调用会回溯以产生其他结果,因此perm
会产生额外的结果(因为它调用takeout
回溯,就像它们一样当您手动查询perm
时执行此操作。
takeout
在Prolog中被实现为takeout
的标准谓词。