【问题标题】:Prolog, permutation code understandingProlog,排列代码理解
【发布时间】:2015-11-13 12:02:01
【问题描述】:

我正在尝试了解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]

这里我不知道为什么程序没有结束,递归完成了,为什么takeoutperm又工作了?

之后takeout 被称为takeout(1, [2,3])

现在哪个适用于takeout(X,[F |R],[F|S]) 而不适用于takeout(X,[X|R],R).,这是我的第二个问题,为什么?

【问题讨论】:

  • 在 Prolog 中,查询或谓词调用将尝试找到 所有 可能的解决方案,而不仅仅是一个然后结束。因此,即使看起来他们结束了,他们也留下了一个选择点,在这个选择点上,其他成功的选择都是可能的。 Prolog 会自动返回这些选择点并提供备选方案。这是 Prolog 强大功能的一部分。
  • @lurker 谢谢 :)

标签: list prolog


【解决方案1】:

在 Prolog 中,谓词的行为与过程语言中的函数完全不同。 函数被调用来执行任务,它执行,然后返回一些值或执行了一些副作用,或两者兼而有之。

谓词定义了一个关系和/或一组事实,这些事实在它的论点之间建立了逻辑联系。当对 Prolog 中的谓词进行查询时,Prolog 将尝试查找参数变量的每个实例,这些实例将使该谓词成功(为真)。

在一个非常简单的情况下,我可能有以下事实:

likes(tom, mary).    % Tom likes Mary
likes(fred, mary).   % Fred likes Mary

这里我有一个谓词或事实,likes,它定义了两个人之间的关系。我们称上面的 facts 是因为它们每个都指定了一个具有完全实例化参数的精确、具体的关系。我可以进行如下查询以确定谁喜欢 Mary?

| ?- likes(Person, mary).

Person = tom ? ;

Person = fred

yes

查询首先返回Person = tom,但表明一旦发现Person = tom 满足查询,它就有更多选项可供检查。输入 ; 告诉 Prolog 继续下一个解决方案(如果有的话),它会找到它:Person = fred

现在让我们考虑takeout/3。这是一个谓词,它定义了一组变量之间的关系

  1. takeout(X,[X|R],R).
  2. takeout(X,[F|R],[F|S]) :- takeout(X,R,S).

takeout/3 谓词有两个 谓词子句规则 用于关系。尝试阅读它们会很有帮助:

  1. 如果您从[X|R] 中取出X,就会得到R
  2. [F|S] 是你从[F|R] 中取出X 得到的结果 if S 是你从X 中取出X 得到的结果。

Prolog 以分离的方式查看多个子句。也就是说,如果任何一个规则可以成立,则对谓词的查询或调用将成功。当对takeout/3 进行查询时,Prolog 将在查询中查找给定变量的实例,这将使其成为真的,并且它会尝试找到 每个 这样做的实例。换句话说,如果满足条件的方法不止一种,它会回溯并尝试找到那些这样做的变量实例化。

考虑查询:

?- takeout(X, [1,2,3], R).

Prolog 能够通过实例化 X = 1R = [2,3] 将其匹配到第一个谓词子句:takeout(X, [X|R], R) as takeout(1, [1,2,3], [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) 匹配,匹配成功与X = 2S = [3]takeout(2, [2|[3]], [3]).。递归展开或返回(就像在任何语言中一样),前一个调用头 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 的调用会产生额外的结果,就像他们通过查询takeout 时所做的那样手)。


正如@false 所指出的,谓词takeout/3 在Prolog 中作为标准谓词实现为select/3

【讨论】:

  • 这个外卖俗称select/3
  • @false 确实,我认得。 :)
猜你喜欢
  • 2018-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-20
  • 2021-02-24
  • 1970-01-01
相关资源
最近更新 更多