如何防止循环一次后递归



我刚刚意识到这是一个愚蠢的问题。很好奇是否有人还能找到漏洞。

源代码:

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),!.

我希望它做的是再次尝试结婚(普京,特朗普),但所有早期的基本情况都将再次失败。我们之前尝试切换参数并失败了。所以不要递归。只需返回假。

我收到一个堆栈错误,因为直到结婚(普京,特朗普)或其他方式!永远不会返回真或假,所以切割将无法触发。

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

任何见解都会很棒,谢谢。

你走在正确的轨道上,"切换参数一次,如果失败则返回失败",尽管这是非常命令式的,并没有涵盖我们期望从这种关系中获得的所有模式。

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

一、助词

married_(a, b). married_(c, d). 等。

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

已婚(X,Y) :- married_(X,Y)。 已婚(X, Y) :- married_(Y, X).

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

示例查询:

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

严格来说,你当然也可以只用一个谓词来做到这一点,但是如果你这样做 ,你需要随身携带额外的信息。

例如:

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

示例查询:

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

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

最新更新