Prolog 谓词中的[H | |和[| T]是如何工作的?

Prolog 谓词中的[H | |和[| T]是如何工作的?,prolog,predicate,clause,Prolog,Predicate,Clause,我仍然在学习Prolog,我遇到了这个小代码片段,我不知道我是否理解正确 代码: %将蜘蛛交给朋友,并返回一个彼此不认识的人的列表。 获取共谋者[],Res,Res。 获取共谋者[H | T]、协调者、回复者:- 追加[H | T],C调查员,主键, 知道卫星斯通PK, %找到可能的同谋H的所有朋友。 所有的朋友,朋友们, 减去T,p朋友,Pprim, 获取共谋者Pprim,[H | CConpirators],Res。 获取共谋者[124; T]、协调者、回复者:- 获取共谋者T、共谋者、Re

我仍然在学习Prolog,我遇到了这个小代码片段,我不知道我是否理解正确

代码:

%将蜘蛛交给朋友,并返回一个彼此不认识的人的列表。 获取共谋者[],Res,Res。 获取共谋者[H | T]、协调者、回复者:- 追加[H | T],C调查员,主键, 知道卫星斯通PK, %找到可能的同谋H的所有朋友。 所有的朋友,朋友们, 减去T,p朋友,Pprim, 获取共谋者Pprim,[H | CConpirators],Res。 获取共谋者[124; T]、协调者、回复者:- 获取共谋者T、共谋者、Res。 %检查Y或Y的朋友是否认识PK中的任何人。 knowsAtleastOne PK:- forall personY,memberchkY,PK;友谊,PK。 %检查某人X的朋友是否认识任何共谋者。 朋友们,共谋者:- 朋友X,Y, 成员,共谋者, !. 这不是整个程序,只是其中的一小部分

我不确定我是否理解了本文件的以下部分:Get阴谋者[H | T]、CConspirators,Res:-和GetConfirators[|T]、CConspirators,Res:-部分
getconcurrators谓词。他们看起来几乎一样!现在,我知道u符号的字面意思是任何值,也就是Prolog,并不关心它是什么值。但是Prolog如何知道在运行代码时选择哪种情况呢?我的理论是,Prolog运行getConcerrators[|T],cConcerpirators,Res:-案例当且仅当getConcerrators[H | T],cConcerpirators,Res:-案例失败时在某个地方返回false。我理解正确了吗?

这里有三个要素:回溯、统一和列表符号。我将用一个简单的例子来解释这三个问题:

moon(europa).
moon(ganymede).

planet(jupiter).
planet(saturn).
我们知道木卫二和木卫三是木星的两颗卫星,木星和土星是行星。当我们询问已知的行星时,我们写道:

?- planet(X).
X = jupiter ;  % type ; for the next answer
X = saturn.    % there's no more answer, hence .
当prolog寻找适合查询的规则头时,就会发生统一,在查询中相应地替换变量。例如,没有替代物使moonX=planetY相等,但planetjupiter=planetX有一个替代物,即X=jupiter。这就是获得第一个解的方法。对于第二个解决方案,Prolog需要与第二个规则头统一,即PlanetsTurn=planetX。因为这是在第一个选项完全枚举后完成的,所以我们称之为回溯

现在我们可以关注链表。列表要么为空[],要么在尾部列表Xs[X | Xs]前面有第一个元素X。Prolog还有一个更好的列表符号[X |[Y |[]],即[X,Y]。在内部,它们是相同的。当我们现在想要收集星体物体列表时,我们可以制定以下三条规则:

astral_objects([]).        % The empty list is a list of astral objects.

astral_objects([X|Xs]) :-  % The list [X | Xs] is a list of astral objects if...
    moon(X),               % ... its first element X is a moon
    astral_objects(Xs).    % ... and the remaining list Xs is a list of astral objects

astral_object([X|Xs]) :-   % Likewise for planets
    planet(X),
    astral_objects(Xs).
当我们为两元素列表制定查询时,我们得到了所有对象的组合:

?- astral_object([A,B]).
A = B, B = europa ;
A = europa,
B = ganymede ;
A = europa,
B = jupiter ;
A = europa,
B = saturn ;
A = ganymede,
B = europa ;
A = B, B = ganymede ;
A = ganymede,
B = jupiter
%...
通过统一,只有规则2和3适用。在这两种情况下,我们都有星体对象[X | Xs]=星体对象[A,B]。记住,[A,B]是[A |[B]]的简写,这里是X=A和Xs=[B]的简写。天体的第一条规则将X与相应的月球/行星统一起来,递归步骤描述了尾部。同样,我们统一了星体对象[X | Xs]=星体对象[B],从而得到X=B和Xs=[]。现在,递归步骤将只匹配空列表的终端情况,我们已经充分探索了这条路径

现在,如果我们寻找星体物体的任意列表,会发生什么

?- astral_object(Xs).
Xs = [] ;
Xs = [europa] ;
Xs = [europa, europa] ;
Xs = [europa, europa, europa] ;
Xs = [europa, europa, europa, europa] ;
Xs = [europa, europa, europa, europa, europa] 
%... does not terminate
头部星体与所有三个身体相匹配。在返回对终端案例的替换之后,它会一次又一次地下降到第一个规则中。由于列表的长度是不受限制的,所以在尝试第三条规则之前,需要找到无限多的解。为了避免这种情况,您可以在尝试使列表满足谓词之前公平地枚举列表:

?- length(Xs,_), astral_object(Xs).
Xs = [] ;
Xs = [europa] ;
Xs = [ganymede] ;
Xs = [jupiter] ;
Xs = [saturn] ;
Xs = [europa, europa] ;
Xs = [europa, ganymede] ;
Xs = [europa, jupiter] ;
Xs = [europa, saturn] ;
Xs = [ganymede, europa]
%...

它仍然没有终止,但是你可以看到列表的长度是递增的,因此是多样的。

这里有三个因素在起作用:回溯、统一和列表符号。我将用一个简单的例子来解释这三个问题:

moon(europa).
moon(ganymede).

planet(jupiter).
planet(saturn).
我们知道木卫二和木卫三是木星的两颗卫星,木星和土星是行星。当我们询问已知的行星时,我们写道:

?- planet(X).
X = jupiter ;  % type ; for the next answer
X = saturn.    % there's no more answer, hence .
当prolog寻找适合查询的规则头时,就会发生统一,在查询中相应地替换变量。例如,没有替代物使moonX=planetY相等,但planetjupiter=planetX有一个替代物,即X=jupiter。这就是获得第一个解的方法。对于第二个解决方案,Prolog需要与第二个规则头统一,即PlanetsTurn=planetX。因为这是在第一个选项完全枚举后完成的,所以我们称之为回溯

现在我们可以关注链表。列表要么为空[],要么在尾部列表Xs[X | Xs]前面有第一个元素X。Prolog还有一个更好的列表符号[X |[Y |[]],即[X,Y]。在内部,它们是 相同的当我们现在想要收集星体物体列表时,我们可以制定以下三条规则:

astral_objects([]).        % The empty list is a list of astral objects.

astral_objects([X|Xs]) :-  % The list [X | Xs] is a list of astral objects if...
    moon(X),               % ... its first element X is a moon
    astral_objects(Xs).    % ... and the remaining list Xs is a list of astral objects

astral_object([X|Xs]) :-   % Likewise for planets
    planet(X),
    astral_objects(Xs).
当我们为两元素列表制定查询时,我们得到了所有对象的组合:

?- astral_object([A,B]).
A = B, B = europa ;
A = europa,
B = ganymede ;
A = europa,
B = jupiter ;
A = europa,
B = saturn ;
A = ganymede,
B = europa ;
A = B, B = ganymede ;
A = ganymede,
B = jupiter
%...
通过统一,只有规则2和3适用。在这两种情况下,我们都有星体对象[X | Xs]=星体对象[A,B]。记住,[A,B]是[A |[B]]的简写,这里是X=A和Xs=[B]的简写。天体的第一条规则将X与相应的月球/行星统一起来,递归步骤描述了尾部。同样,我们统一了星体对象[X | Xs]=星体对象[B],从而得到X=B和Xs=[]。现在,递归步骤将只匹配空列表的终端情况,我们已经充分探索了这条路径

现在,如果我们寻找星体物体的任意列表,会发生什么

?- astral_object(Xs).
Xs = [] ;
Xs = [europa] ;
Xs = [europa, europa] ;
Xs = [europa, europa, europa] ;
Xs = [europa, europa, europa, europa] ;
Xs = [europa, europa, europa, europa, europa] 
%... does not terminate
头部星体与所有三个身体相匹配。在返回对终端案例的替换之后,它会一次又一次地下降到第一个规则中。由于列表的长度是不受限制的,所以在尝试第三条规则之前,需要找到无限多的解。为了避免这种情况,您可以在尝试使列表满足谓词之前公平地枚举列表:

?- length(Xs,_), astral_object(Xs).
Xs = [] ;
Xs = [europa] ;
Xs = [ganymede] ;
Xs = [jupiter] ;
Xs = [saturn] ;
Xs = [europa, europa] ;
Xs = [europa, ganymede] ;
Xs = [europa, jupiter] ;
Xs = [europa, saturn] ;
Xs = [ganymede, europa]
%...

它仍然没有终止,但是你可以看到列表的长度是递增的,因此是多样的。

问题是getconcerrators[H | T]、cConcerrators、Res:-(u body)和getconcerrators[| T]、cConcerrators、Res:-(u body)部分。。。我的理论是,Prolog运行getConcerrators[|T],cConcerpirators,Res:-案例当且仅当getConcerrators[H | T],cConcerpirators,Res:-案例失败时返回false

你的理论是错误的。他们两个都会匹配。唯一的区别是,对于getconcurrators[H | T]、cconpirators、Res:-(u body)的情况,列表的第一个元素将作为名为H的变量在body中可用。但是对于getconcerrators[124; T]、cConcerpirators、Res:-body,列表的第一个元素在主体中不能作为命名变量使用。
解释此代码中演示的|的含义的一个好方法是一个变量,我不想在后面提及。

所问的问题是getconcerators[H | T]、cConcertiators、Res:-(u body)和getconcertiators[| T]、cConcertiators、Res:-(u body)部分。。。我的理论是,Prolog运行getConcerrators[|T],cConcerpirators,Res:-案例当且仅当getConcerrators[H | T],cConcerpirators,Res:-案例失败时返回false

你的理论是错误的。他们两个都会匹配。唯一的区别是,对于getconcurrators[H | T]、cconpirators、Res:-(u body)的情况,列表的第一个元素将作为名为H的变量在body中可用。但是对于getconcerrators[124; T]、cConcerpirators、Res:-body,列表的第一个元素在主体中不能作为命名变量使用。
如本代码所示,解释u的含义的一个好方法是一个变量,我不想在后面提及。

不,Prolog可以使用回溯,但它可以做到这一点,而不管前面的子句是否有效/失败,除非您使用诸如cut!之类的东西@你能再详细解释一下吗?我是一个Prolog新手:我认为如果不了解更简单的Prolog谓词,简单地解释这段代码是很困难的。Prolog作为一种编程语言有点独特:它是声明性的,内置回溯,谓词是多向的,所有这些功能的组合往往很难理解。@WillemVanOnsem所以如果GetConcerators[H | T],CConpirators,Res:-部分被切掉了!在其递归调用之前,将其放置在何处是否重要?如果在运行时出现故障,它将停止在那里运行代码,并跳转到下一个子句getconcurrators[124; T],cconpirators,Res:-?但是如果没有像这里这样的剪切,它会在第一条之后每次运行最后一条,不管发生什么?因此,如果所有这些都是正确的,那么第二个子句的任务就是简单地跳转到列表中的下一个元素,就像for循环一样?从更小的程序开始。不,Prolog可以使用回溯功能,但是它可以做到这一点,而不管前一个子句是否有效/失败,除非使用诸如cut!之类的东西@你能再详细解释一下吗?我是一个Prolog新手:我认为如果不了解更简单的Prolog谓词,简单地解释这段代码是很困难的。Prolog作为一种编程语言有点独特:它是声明性的,内置回溯,谓词是多向的,所有这些功能的组合往往很难理解。@WillemVanOnsem所以如果GetConcerators[H | T],CConpirators,Res:-部分被切掉了!在其递归调用之前,将其放置在何处是否重要?如果在运行时出现故障,它将停止在那里运行代码,并跳转到下一个子句getconcurrators[124; T],cconpirators,Res:-?但是如果没有像这里这样的剪切,它会在第一条之后每次运行最后一条,不管发生什么?所以如果所有 当然,第二个子句的任务是简单地跳转到列表中的下一个元素,就像for循环一样?从更小的程序开始。