前言:失败驱动循环

Zor*_*ran 4 prolog logic-programming prolog-setof

我使用以下失败驱动循环来列出所有内容,而无需使用分号。

happiness(fred,5).
happiness(john,3).
happiness(grace,2).

someGoal(X) :-
        happiness(X,Y), write(Y), tab(4), fail.
Run Code Online (Sandbox Code Playgroud)

在查询模式下,我得到了预期的结果

?- someGoal(_).
5    3    2 
Run Code Online (Sandbox Code Playgroud)

如何将这些数字插入列表中,而不是将它们写到屏幕上?someGoal由于回溯似乎是隐式的,因此我无法在内部进行处理。

Cap*_*liC 5

没错,回溯是Prolog处理替代方案的方式。

使用findall / 3,它使用“内部”回溯来收集所有替代项:

someGoal(X, Values) :-
    findall(Value, happiness(X, Value), Values).
Run Code Online (Sandbox Code Playgroud)

然后?- someGoal(_, Values).实例值= [5、3、2]


fal*_*lse 5

故障驱动的循环通常会使某些部分处于开放和未指定状态,迟早会导致一些问题。特别是变量的精确量化很容易保持开放。通常,可以完全避免此类循环。在你的例子中,我不清楚你为什么要争论someGoal/1。至少你不用它。于是出现了几个问题:

  1. 如果没有匹配值,您期望什么?您的原始程序不打印任何内容并失败。

  2. 如果有多余的条目,您期望什么?你想多次打印东西吗?

  3. 你坚持价值的精确顺序,还是你能想象另一种顺序?

  4. 为什么您对查看这些值感兴趣?大多数情况下,您要么希望看到它们与具体名称相关联,要么希望对其进行某种聚合,例如总和或平均值。

鉴于我不知道这些问题的答案,我可以为您提供几种解决方案。我将用一个额外的(冗余的)事实来举出你的例子:

幸福(弗雷德,5)。
幸福(约翰,3)。
幸福(约翰,3)。
幸福(恩典,2)。

?- setof(PH,happiness(P,H), PHs)。
PHs = [fred-5,grace-2,john-3]。

?- setof(H,P^happiness(P,H), PHs)。
PHs = [2, 3, 5]。

?- bagof(H,P^happiness(P,H), PHs)。
PHs = [5, 3, 3, 2]。