Prolog 序言:列出一个事实

Prolog 序言:列出一个事实,prolog,Prolog,假设我在找某人的朋友 friend(mary, peter). friend(mary, paul). friend(mary, john). friend(mary, justin). friend(chris, peter). friend(chris, paul). friend(chris, conner). friend(chris, louis). friend(tyler, justin). friend(tyler, lindsey). friend(tyler, frank

假设我在找某人的朋友

friend(mary, peter).
friend(mary, paul).
friend(mary, john).
friend(mary, justin).

friend(chris, peter).
friend(chris, paul).
friend(chris, conner).
friend(chris, louis).

friend(tyler, justin).
friend(tyler, lindsey).
friend(tyler, frank).
friend(tyler, paul).

friend(dan, justin).
friend(dan, conner).
friend(dan, frank).
friend(dan, peter).
在上面的例子中,我知道我可以这样做

friend(X, paul).
findall(A, friend(A, peter), B).
这会告诉我保罗是谁的朋友

或者也

findall(X, friend(X, paul), L).
这将返回保罗的朋友名单

比方说,我想在我的搜索中更深入一点,并对其进行改进。所以让我们说,我是要做的

findall(X, friend(X, paul), A).
得到一张名单,成为[玛丽、克里斯、泰勒]的一员。但后来我想进一步完善这个搜索。我希望能够将列表放入函数中(我知道这是无效的,但这是我想做的事情的思维模式),比如

friend(X, paul).
findall(A, friend(A, peter), B).
这次就回来[玛丽,克里斯]。然后进一步细化到

findall(B, friend(B, conner), C).
最终结束我对[chris]的搜索

这可能吗?是否有更好甚至可能的方法来实现这一点?

链条件 如果我理解正确,您希望生成一个与
paul
peter
connor
为好友的列表。我们可以通过“构建”一个目标来实现这一目标,该目标旨在满足以下三个条件:

findall(F, (friend(F, paul), friend(F, peter), friend(F, conner)), L).
使用目标中的
成员/2
筛选现有列表 或者我们也可以使用两个调用,并使用
member/2
来“模拟”交叉口,如:

findall(F, friend(F, paul), L1),
findall(F, (member(F, L1), friend(F, peter)), L2).
具有交叉点的后处理 我们还可以进行两次单独的
findall/3
调用,然后计算交点:

findall(F, friend(F, paul), L1),
findall(F, friend(F, paul), L2),
intersection(L1, L2, M).

这里
M
将包含
L1
L2
中的元素。但这里的一个潜在问题是,第二个谓词可能会生成许多结果,而这些结果在给定的情况下是不可能的,因为我们使用了第一个谓词的值进行了筛选。

我们走在了正确的轨道上。除了我希望用户能够说“通过添加另一个朋友来优化搜索”,以缩小我要寻找的最终一个人或多个人的范围。所以我尝试递归地调用一个函数,它不断地向列表中添加一个朋友。就像他们第一次说保罗。然后返回一个列表,并通过说peter来优化搜索。然后第三次打电话给康纳,或者如果他们想停在前两个名字上,对[玛丽,克里斯]的名单感到满意的话,可以对它进行改进。我的解决办法是一直按L键,表示只从这个特定列表中搜索。@Justin:这是第二个策略:因此,我们在第一个列表(
L1
)上使用
member/2
)来进一步过滤这个列表。但是请注意,您不需要一个接一个地调用
findall/3
s,第二个findall是一个“细化器”。@Justin:此外,如果您想要处理一个人员列表,那么第三种方法可能是最优雅的。限制是,每次您想要添加新名称进行搜索时,都必须重新定义查询。如果我能以某种方式把清单L推到事实上,说findall(L,(朋友,保罗),M)。其中L是第一次循环生成的列表,M是新列表,我可以用一行代码递归调用它。这对我试图完成的工作有意义吗?然后我要改变的是paul,它可能来自变量X。@Justin:但在这里,你用一行代码,就可以编写
findall(F,(member(F,l),friend(F,peter)),M)。您只使用
member/2`稍微扩展了“目标”,但这并不真正“限制”更改各种目标的自由。