3

我正在我的大学学习 Prolog,但我遇到了一个问题。请注意,我是 Prolog 的新手,我什至不知道 Prolog 元素的正确拼写。

我需要在我的 .pl 文件中定义一个递归规则,我不知道我是否需要在我的规则上添加一个“基本步骤”。检查我的规则:

recur_disciplinas(X, Y) :- requisito(X, Y).
recur_disciplinas(X, Y) :- requisito(X, Z), recur_disciplinas(Z, Y).

这是有效的,但我不能做类似下面的事情吗?

recur_disciplinas(X, Y) :- requisito(X, Z), recur_disciplinas(Z, Y).

当我recur_disciplinas(X,Y) :-两次声明相同的“规则名称”( ) 时会发生什么?发生有点像覆盖?

我目前正在使用swi-prolog。十分感谢大家!

4

3 回答 3

4

理解 Prolog 规则的最好方法是查看:-1970 年代的箭头渲染运算符(是的,:=Pascal 中的赋值运算符也意味着箭头)。所以你看看右边是什么,然后说:如果一切都是真的,我可以得出左边是什么的结论。所以你正在阅读你的规则从右到左:

 recur_disciplinas(X, Y) :- requisito(X, Z), recur_disciplinas(Z, Y).
 %                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ read

你说:如果有一些XY并且Z使得右手为真,我们可以得出结论recur_disciplians(X, Y)成立。现在,让我们通过删除requisito(X, Z). 现在剩下的是:

 recur_disciplinas(X, Y) :- /******/ recur_disciplinas(Z, Y).

因此,您可以从中得出recur_disciplinas(Z, Y)结论recur_disciplinas(X, Y)。但是你没有什么可以从这个结论开始的!如此有效地,这意味着根本没有解决这种关系的办法。

就像说,只要我能飞,我就会像鸟一样飞。

也许这是真的,但只要你不飞,一切都是徒劳的。

请参阅this answer如何允许更紧凑地表达您的关系。一个目标closure(requisito, X, Y)就够了!它甚至可以处理潜在的循环。


作为旁注,我怀疑这recur是一些动词,甚至是命令式。对?尽量避免关系的必要性。命令式有利于改变事物。就像“开灯”一样,它将世界从关灯的世界变成了开灯的世界。命令式有利于告诉一个没有头脑的实体该做什么。如果你更想对事物进行推理,那么命令就是不恰当的。相反,应该关注什么应该是这样,什么不是。

于 2015-09-01T08:24:37.747 回答
1

如果您有多个规则名称,它会在您的控制流中创建一个或分支。Prolog 将尝试统一第一个子句。如果失败,它将尝试第二个子句,第三个,依此类推。

在上面的代码中,recur_disciplinas规则将首先尝试找到匹配的requisito. 如果它失败了,它将尝试以传递和递归的方式找到一个 requisito-of-a-requisito。

如果不放基子句,Prolog 会一直尝试递归子句,因此可能会进入死循环。

编写基本条件并不是 Prolog 独有的。每种允许递归的语言都是一样的。如果没有停止条件,您的函数将进入无限循环。

考虑这个等效的过程伪代码:

def find_disciplinas(X, Y):
  if find_requisito(X,Y): # halting condition
    return (X, Y)
  else: # recursive call
    for all Z such that find_requisito(X, Z):
      return find_disciplinas(X, Z)

如果您的“requisito”记录包含一个循环,并且您删除了停止条件,则上述过程将无限循环。

于 2015-09-01T06:19:24.887 回答
1

这里我们说recur_disciplinas/2is 一个带有两个参数的谓词,你问过谓词的两个子句(规则)是否是必要的。

正如其他答案所说,在递归中需要一个“基本情况”,以便递归终止,这通常是可取的!最常见的安排就像您的第一个示例:第一条规则是终止条件(基本案例),第二条规则是递归步骤(归纳案例)。阅读您的代码的人可能会发现这种安排熟悉且易于理解。

然而,基本情况和递归步骤可以组合成一个规则,这有时很有用。例如,我们可以使用 OR 语法:

recur_disciplinas(X, Y) :-
    requisito(X, Y) ; ( requisito(X, Z), recur_disciplinas(Z, Y) ).

这里;的意思是 OR,这个单一规则产生的解决方案搜索与原来的双规则版本基本相同。

也可能存在多个基本案例,每个案例都有自己的规则或写入更复杂的“组合”规则。与任何编程学科一样,清晰性和正确性应该比代码的简洁性更重要。

在一些不寻常的情况下,将递归步骤定位为第一条规则,并将基本案例(或多个案例)移动到以下规则中可能是有利的。这需要格外小心以确保始终达到终止条件,因为您不太可能需要可以无限循环的代码。当调用谓词时,Prolog 引擎总是从第一条规则开始;以下规则仅在第一条规则失败时才尝试。

于 2015-09-04T14:09:49.100 回答