如何从 GNU prolog 中的列表中读取?

bac*_*ard 1 prolog

所以我有一个任务,我要在 3 个不同的人之间产生兼容的会议时间。在我定义谓词的 prolog 文件中,有一行给出了我应该比较的三个人的名字,内容如下:

people([ann,bob,carla]).
Run Code Online (Sandbox Code Playgroud)

我们应该从定义事实的数据文件中匹配这些名称,其中事实具有以下格式:

free(ann,slot(time(7,0,am),time(9,0,am))).
Run Code Online (Sandbox Code Playgroud)

我的问题是,我如何通读“人物”以便我可以将姓名相互匹配?

我的教科书并没有很好地解释序言,我对“人”实际上是什么感到困惑(当我说它实际上是什么时,我的意思是“人”是一个列表?一个数组?)所以我遇到了麻烦甚至寻找有关如何通读每个名称的解决方案,以便我可以比较它们。

DuD*_*uDa 5

people([ann,bob,carla]).是事实。谓词people/1包含一个人名列表。在 prolog 中,您可以通过不同的方式从列表中获取元素。

最“脏”的版本只是用固定数量的元素编写列表:

?- people([P1,P2,P3]).
P1 = ann,
P2 = bob,
P3 = carla ;
false.
Run Code Online (Sandbox Code Playgroud)

您不应该这样做,因为它仅适用于 3 人一组,并且每次有人离开/进入时您都必须更改您的代码。

通常你会通过一个序言列表,在那里你只得到第一个元素Head和列表的其余部分Tail

?- people([Head|Tail]).
Head = ann,
Tail = [bob, carla] ;
false.
Run Code Online (Sandbox Code Playgroud)

通过重做这个,你可以遍历整个列表,直到列表只剩下一个元素。为此,您需要一个帮助谓词,我将其命名为person. person将列表作为第一个元素,将变量(或测试名称)作为第二个元素。它将变量与列表中的一个元素统一起来:

person([H|_], H).
person([_|T], P):-
    person(T, P).

?- people(L), person(L,P).

L = [ann, bob, carla],
P = ann ;

L = [ann, bob, carla],
P = bob ;

L = [ann, bob, carla],
P = carla ;

false.
Run Code Online (Sandbox Code Playgroud)

它的工作原理如下:您有一个列表,并假设您只看到其中的第一个元素。您在这里有两个选择:首先,您可以只将 head 元素作为输出,因此第二个属性应该与 head 元素完全相同:person([H|_], H).
或者第二个:您忽略 head 元素并尝试在其余元素中找到一些东西只需使用较小的列表再次调用谓词即可:person([_|T], P):- person(T, P).
当变量以下划线开头时,_您对其内容不感兴趣。

同样值得了解的是:有(最有可能的)内置辅助谓词,例如member/2可以返回列表中的任何成员:

?- people(L), member(P,L).
Run Code Online (Sandbox Code Playgroud)

会给你任何人L

要访问选定人员的单个时间段,您只需free从列表中向您的人员询问谓词:

?- people(L), member(P,L), free(P,S).
Run Code Online (Sandbox Code Playgroud)

如果您想找到列表中所有人员都必须参与的时间段,您需要定义一个辅助谓词。我给它起了名字hastime

hastime([],_).
hastime([H|L], S):-
    free(H,S),
    hastime(L,S).
Run Code Online (Sandbox Code Playgroud)

的输出?- people(L), free(_,S), hastime(L,S).将为您提供一个每个人S都有时间的时间段。在打电话之前hastime/2你先猜一个时间段Shastime/2将查看是否所有人都有时间S:如果没有人(空列表[]),您可以接受任何时间段(_)。如果H您的列表中至少有一个人:询问是否H有时间在时间​​段上,并通过调用尾列表的谓词来S尝试列表中的其他人是否也有这个时间段S空闲。
如果 prolog 选择了一个不是所有人都有时间的时隙S,它将返回到它选择时隙的点并寻找不同的值并重试。如果没有这样的时隙将返回false.
同样hastime/2 可以用来自己找时隙,但是把它当做“生成器”,同时测试有点让人迷惑。