Prolog和列表统一

时间:2015-01-26 16:49:55

标签: prolog unification

我正在努力进一步了解Prolog,以及它如何处理统一。在这种情况下,它如何处理与列表的统一。

这是我的知识库;

member(X, [X|_]).
member(X, [_|T]):- member(X, T).

如果我正确理解了这个过程。如果member(X, [X|_])不成立,则会进入递归规则,如果X位于列表T中,则[_|T]T统一。< / p>

那么我的递归谓词中的匿名变量会发生什么?它被丢弃了吗?我很难理解与列表的确切统一过程,因为[_|T]是两个变量,而不是一个变量。我只想弄清楚统一过程如何与列表精确协作。

4 个答案:

答案 0 :(得分:2)

假设_Y

member(X, [Y|T]):- member(X, T).

无论True如何,这都是Y。现在你正在“回归”member(X, T)。换句话说,您正在放弃Y和“返回”member(X, T).

_表示无论如何,忽略该变量。

  

_就像任何其他变量一样,除了你看到的每个变量   作为一个不同的变量处理,Prolog不会告诉你它是什么   与...结合。那里没有特别的行为;如果它让你感到困惑   关于行为,只需发明一个全新的变量并把它   在那里看看它做了什么。

在您的情况下,您的函数检查列表中是否存在给定元素,因此,您获取列表的第一个元素,检查是否相等,如果不相等,则丢弃该元素并继续。

答案 1 :(得分:2)

我认为关于列表如何表示为变量的主要问题已得到充分回答,但我觉得Prolog还有其他一些方面需要澄清。

要理解Prolog的谓语和从句,不要将它们视为&#34;函数&#34;这是一个好主意。那&#34;返回&#34;事情,甚至比喻。它可以引导你走Prolog中命令式思维的黑暗道路。 :)

在考虑谓词时:

(1) member(X, [X|_]).
(2) member(X, [_|T]) :- member(X, T).

member/2视为 relation ,它描述了元素X何时是列表L的成员,并且子句是用于确定何时的规则这是真的。

我假设你已经知道如何根据其他答案在Prolog中表示列表(例如,Will Ness&#39;详细答案)。

第一个条款说:

(1) X[X|_]的成员,无论列表[X|_]的尾部是什么

在该表示法中,变量_表示列表[X|_]的尾部,X表示该列表的第一个元素。很简单,X是此列表的成员,因此member(X, [X|_]).是事实。无论列表尾部是什么都是如此,因此我们只使用_(匿名变量),因为此规则不需要信息。 Prolog在技术上并没有把价值扔掉#34;程序员因为程序员没有使用它而把它扔掉了。相反,如果我们说member(X, [X|T]).可以正常工作,但我们不会使用T。 Prolog可以实例化它,但它不会被使用。这就像在C中分配x = 3但不使用它的价值一样。在这种情况下,Prolog会发出关于&#34;单身人士的警告。变量。注意那些,因为它通常意味着你拼写错误的东西或忘记了一些东西。 :)

下一个规则是递归的。它说:

(2) X是列表[_|T] 的成员,如果 X是尾部的成员(T)该列表的内容,无论列表的第一个元素是什么

我们在这里考虑的不太重要的情况是列表中的第一个元素可能与X不匹配,因此member(X, L)的真值取决于此规则member(X, T)的真值,其中TL的尾部(除了第一个元素之外的所有元素)。规则member(X, [_|T])member(X, T)统一,因此不会T[_|T]统一起来,因为您可能假设。 :-运算符定义规则或含义(请注意规则说明中的 if )。 [ NB ,如果您统一这些条款,则可以使用统一运算符=/2完成:{{ 1}}]。

在递归查询member(X, [_|T]) = member(X, T)上,Prolog回到顶部,即第一个规则,并尝试将第一个参数member(X, T)与第二个参数的头部统一(这是原始列​​表减去它的第一个元素,或 head ),如果它不匹配,再次进入规则#2,不断检查尾部,直到它可以统一。如果它到达尾部为空(X)并且无法将[]与任何元素统一起来,则谓词将失败,因为没有匹配的事实或规则{ {1}}。但是,如果它确实将X与元素统一,则成功&#34;在某个函数意义上返回值*在其他语言中)并显示它在进程中的参数中实例化的任何变量的值,或者只是在传递的所有参数都已实例化时才会成功。如果成功后需要检查更多规则(有什么称为选择点),它会(如果你告诉它)返回并检查更多解决方案,如果是找到它们,也显示它们。如果没有,请显示member(X, [])X

查看示例查询, nofalse 的成员吗?

b

Prolog将首先尝试使用谓词的 fact head 来统一查询。它找到的第一个是:

[a,b,c]

在尝试统一时,member(b, [a,b,c]). ,但member(X, [X|_]). (或,X = b在头尾符号中)并不与[b | _] {{1 } [a,b,c] b`不匹配)。 Prolog然后转到下一个条款:

[a|[b,c]]

(note the head elements与头部统一时,它会出现:

and

它现在有追逐的递归查询:member(X, [_|T]) :- member(X, T). 。由于它是一个新查询,它会再次从顶部开始,并尝试将其与member(b, [a,b,c])统一起来。现在,它取得了成功,因为member(b, [_|[b,c]]) :- member(b, [b,c]). (或member(b, [b,c]))符合此模式:member(X, [X|_])

因此,member(b, [b,c])成功,Prolog将返回&#34; true&#34;。但是,它还没有完成,因为它留下了所谓的选择点。即使它与member(b, [b|[c]])匹配第一个条款,它仍然希望返回并找到更多使其成功的案例,并且还有另一个条款要追求。因此,Prolog将返回并针对第二个子句尝试member(b, [b|_]),将member(b, [a,b,c]).member(b, [b,c])匹配并执行另一个递归查询member(b, [b,c]),依此类推,直到最终无法找到另一种方案。这就是查询看起来像这样的原因:

member(b, [b|[c]])

它首先成功,但随后我们要求更多(使用member(b, [_|[c]]))然后失败(member(b, [c]))。这让一些Prolog初学者感到困惑,但这是因为我们已经要求Prolog获得另一种解决方案,而且它说没有。

因为Prolog继续尝试寻找解决方案(根据要求),您还可以在查询中使用变量:

| ?- member(b, [a,b,c]).

true ? ;

no
| ?-

此查询的运行方式与前一个示例相同,但现在我将变量作为第一个参数。 Prolog会将此成功与第一个条款匹配:;通过nomember(E, [a,b,c]). 统一。所以你会看到类似的东西:

member(E, [a,b,c])

如果我们现在要求使用member(X, [X|_])提供更多解决方案,Prolog会回过头来尝试第二个条款,将E = a| ?- member(E, [a,b,c]). E = a ? 统一;(在此处忽略谓词)和member(E, [a|[b,c]])。然后递归查询member(X, [_|T]),并且由于它是新查询,因此返回到顶部并再次匹配_ = a,这次是T = [b,c]。所以我们看到:

member(E, [b,c])

等等。 member(X, [X|_])会找到E = b使| ?- member(E, [a,b,c]). E = a ? ; E = b ? 为真的所有值,然后在耗尽member(E, [a,b,c])的所有元素后最终失败。

答案 2 :(得分:1)

列表只是'.'仿函数的复合词:

1 ?- [_|T] = .(_,T).
true.

2 ?- [_|T] =.. X.
X = ['.', _G2393, T].

复合词的结构统一的通常过程适用:

3 ?- [A|T] = .(B,R). 
A = B,
T = R.

[A|T]实际上是.(A,T)所以仿函数(.)和arities(两个术语都是二元,arity 2)匹配,所以各个成分也匹配。< / p>

是的,为了报告统一结果,将忽略匿名变量_。否则它只是一个新的唯一命名变量。

  

它进入递归规则,如果X在列表T中,则[_ | T]与T统一。

不完全。统一发生在之前&#34;继续&#34;,作为子句选择的一部分。要将列表L统一到[_|T],请选择其尾部&#34;并T引用它。 E.g。

4 ?- L = [1,2,3], L = [_|T].
L = [1, 2, 3],
T = [2, 3].

_1,但未报告。)

答案 3 :(得分:1)

[A|B]表示一个列表,其中A是Head元素,B是整个剩余列表。

所以很快就解释一下这个算法:

  1. 子句:如果X是列表的第一个元素,则谓词成功。
  2. 条款:如果不是这样,我们会尝试在列表的尾部找到X.因此,我们以递归方式调用成员,但不是传递整个列表,而是现在传递列表除了head元素之外。换句话说,我们一步一步地浏览列表,始终首先查看head元素。如果那不是我们的要素,我们会进一步挖掘。
  3. 将匿名变量_想象为您以后不需要的变量。如果您用大写字母替换_,该算法也会起作用,但它会给您一个警告,指出您从未使用过的变量。