2

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

这是我的知识库;

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

如果我正确理解了这个过程。如果member(X, [X|_])不为真,则进入递归规则,如果X在列表中T,则[_|T]与 统一T

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

4

4 回答 4

2

假设_Y

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

那么这就是True不管了Y。现在你“回归”了member(X, T)。换句话说,你正在丢弃Y和“返回”member(X, T).

_意味着,不管它是什么,忽略那个变量。

_ 就像任何其他变量一样,除了您看到的每个变量都被视为不同的变量,Prolog 不会向您显示它与什么相结合。那里没有特殊行为;如果它使您对行为感到困惑,只需发明一个全新的变量并将其放入其中以查看其作用。

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

于 2015-01-26T17:00:51.083 回答
2

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

要理解 Prolog 谓词和从句,最好不要将它们视为“返回”事物的“函数”,即使是隐喻。它可以引导你走上 Prolog 中命令式思维的黑暗道路。:)

在考虑谓词时:

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

可以将member/2其视为描述元素何时是列表成员的关系,子句是确定何时为真的规则。XL

我假设您已经知道基于其他答案(例如,Will Ness 的详细答案)在 Prolog 中列表是如何表示的。

第一个条款说:

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

在该表示法中,变量_表示列表的尾部[X|_]X表示该列表的第一个元素。X是这个列表的成员是微不足道的,事实也是如此member(X, [X|_]).。不管列表的尾部是什么,它都是正确的,所以我们只使用_(一个匿名变量),因为这个规则不需要信息。Prolog 在技术上并没有“丢弃价值”,但程序员将其丢弃是因为程序员没有使用它。相反,如果我们说,member(X, [X|T]).那会很好,但我们没有使用T. Prolog 可能会实例化它,但它不会被使用。这就像分配x = 3在 C 中但不使用它的值。在这种情况下,Prolog 将指示有关“单例”变量的警告。注意那些,因为这通常意味着你拼错了一些东西或忘记了一些东西。:)

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

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

在这里,我们正在考虑一种不太简单的情况,即列表中的第一个元素可能与 不匹配X,因此 的真值在此规则中取决于member(X, L)尾部的真值(除第一个元素之外的所有元素)的。该规则与统一,因此它不像您想象的那样与统一。运算符定义规则或含义(注意规则描述中的if 。[注意,如果你要统一这些术语,它将使用统一运算符完成,: ]。member(X, T)TLmember(X, [_|T])member(X, T)T[_|T]:-=/2member(X, [_|T]) = member(X, T)

在递归查询member(X, T)中,Prolog 回到顶部,第一条规则,并尝试将第一个参数X与第二个参数的头部(原始列表减去它的第一个元素或head)统一起来,如果没有t 匹配,再次进入规则#2,不断检查尾部,直到它可以统一。如果它到达尾部为空 ( []) 并且无法X与任何元素统一的点,则谓词将失败,因为没有匹配的事实或规则member(X, [])。但是,如果它确实X与一个元素统一,它会成功(它不会“在函数在其他语言中的意义上返回一个值*)并揭示它在过程中的参数中实例化的任何变量的值,或者如果传递的所有参数都已实例化,则简单地成功。如果有更多规则成功后检查(有所谓的选择点),它会(如果你告诉它)返回并检查更多解决方案,如果找到它们,也显示它们。或者显示no或者false如果没有更多.

查看示例查询,b的成员[a,b,c]吗?

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

Prolog 将首先尝试将查询与事实或谓词头部统一起来。它找到的第一个是:

member(X, [X|_]).

在尝试统一时,X = b, 但是[a,b,c](或者,[a|[b,c]]在头尾表示法中)没有与 [b|_] (note the head elementsa andb` 不匹配统一)。Prolog 然后转到下一个子句:

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])(or, member(b, [b|[c]])) 匹配此模式:member(b, [b|_]).

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

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

true ? ;

no
| ?-

它首先成功,但随后我们要求更多(with ;),然后它失败了(no)。这让一些 Prolog 初学者感到困惑,但这是因为我们已经要求 Prolog 获得另一个解决方案,它说没有。

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

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

此查询的运行方式与前面的示例相同,但现在我有一个变量作为第一个参数。Prolog 将成功地将其与第一个子句匹配:与viamember(E, [a,b,c])统一。所以你会看到类似的东西:member(X, [X|_])E = a

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

E = a ?

如果我们现在用 请求更多解决方案;,Prolog 会返回并尝试第二个子句,member(E, [a|[b,c]])member(X, [_|T])yielding _ = 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])将找到所有E使member(E, [a,b,c])true 的值,然后在用尽 ) 的所有元素后最终失败[a,b,c]

于 2015-01-27T14:10:49.003 回答
1

列表只是'.'函子的复合术语:

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

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

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

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

[A|T]确实.(A,T)如此,函子 ( .) 和元数(两个项都是二元的,元数为 2)匹配,因此相应的成分也匹配。

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

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

不完全的。作为子句选择的一部分,统一发生“继续”之前。统一一个列表L就是[_|T]选择它的“尾巴”并T引用它。例如

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

_1但未报告)。

于 2015-01-26T16:58:48.097 回答
1

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

因此,简短地向您解释一下算法:

  1. 子句:如果 X 是列表的第一个元素,则谓词成功。
  2. 子句:如果不是这样,我们尝试在列表的尾部找到 X。因此,我们递归地调用 member,但我们现在传递的不是整个列表,而是除了 head 元素之外的列表。换句话说,我们一步一步地遍历列表,总是首先查看头部元素。如果这不是我们的元素,我们会进一步挖掘。

将匿名变量_视为您以后不需要的变量。如果您用大写字母替换,该算法也可以工作,_但是它会给您一个警告,告诉您您命名了一个您从未使用过的变量。

于 2015-01-26T17:02:03.413 回答