0

我才意识到这是一个愚蠢的问题。好奇是否有人仍然可以找到漏洞。

源代码:

married(trump,obama).
married(trump,goat).
married(pepee,pepper).
married(X,Y) :- married(Y,X),!. % not awesome because of infinite recursion

Goal: ex. married(trump, putin).
trace(
first base case fails.
second base case fails.
third base case fails.
married(trump,putin) = married(putin,trump),!.

我想要它做的是再次尝试结婚(普京,特朗普),但所有早期的基本案例都会再次失败。我们之前尝试过切换参数但失败了。所以不要递归。只返回假。

我收到堆栈错误,因为直到结婚(普京,特朗普)或其他方式之前!永远不会返回 true 或 false,因此 cut 将无法触发。

更简单和更理智的方法是重写代码以防止递归。我很好奇是否有办法尝试切换 args 一次,如果失败则返回失败。如果您有很长的事实列表,如果您可以尝试 arg1、arg2,则可以将该长列表减少一半,反之亦然。如果我们得到疯狂的排列场景,可能会呈指数级增长。

任何见解都会非常感谢。

4

1 回答 1

4

您在“切换 args 一次并在失败时返回失败”的正确轨道上,即使这是非常必要的措辞并且并未涵盖我们期望从这种关系中获得的所有模式。

为此,您需要将其分成两个谓词。很容易证明具有给定接口的单个​​谓词是不够的。

一、辅助谓词

已婚_(a,b)。
已婚_(c,d)。
等等

然后,主要谓词,基本上正如您所建议的那样:

已婚(X,Y):-已婚_(X,Y)。
已婚(X,Y):-已婚_(Y,X)。

在您的解决方案中添加杂质会使事情变得更糟:您几乎总是会破坏关系的普遍性,从而提出您为什么要使用声明性语言的问题。

示例查询:

?- 已婚(X,Y)。
X = 一个,
Y = b;
X = c,
Y = d;
X = b,
Y = 一个;
X = d,
Y = c。

严格来说,您当然也可以只使用一个谓词来执行此操作,但如果您这样做,则需要携带额外的信息。

例如:

已婚(_,a,b)。
已婚(_,c,d)。
已婚(第一,X,Y):-已婚(第二,Y,X)。

示例查询:

?- 已婚(_,X,Y)。
X = 一个,
Y = b;
X = c,
Y = d;
X = b,
Y = 一个;
X = d,
Y = c。

这与您描述的方法非常相似:“我们之前尝试过切换参数。所以不要再这样做了。”

于 2017-03-21T22:50:15.870 回答