什么';在prolog中建立自然数规则的正确方法是什么?
我想我在理解prolog时遇到了一些更大的问题,但因为我不能很好地表达它,所以我只关注一个问题 我想创建一个规则什么';在prolog中建立自然数规则的正确方法是什么?,prolog,Prolog,我想我在理解prolog时遇到了一些更大的问题,但因为我不能很好地表达它,所以我只关注一个问题 我想创建一个规则natural(X),如果X是1,2,3,4,… 更重要的是,我希望:natural(5)为true和natural(X)输出X=1;X=2 所以,我解释规则如下(伪逻辑): 或者,就序言而言: natural(1). natural(X) :- natural(X-1). 但是我遇到了一个问题-如果我尝试natural(5)我会得到无限递归 调试器说程序计算: natural(5
natural(X)
,如果X
是1,2,3,4,…更重要的是,我希望:
natural(5)
为true和natural(X)
输出X=1;X=2代码>
所以,我解释规则如下(伪逻辑):
或者,就序言而言:
natural(1).
natural(X) :- natural(X-1).
但是我遇到了一个问题-如果我尝试natural(5)
我会得到无限递归
调试器说程序计算:
natural(5)
natural(5-1)
natural(5-1-1)
natural(5-1-1-1)
natural(5-1-1-1-1)
natural(5-1-1-1-1-1)
natural(5-1-1-1-1-1-1)
...
我想问题出在X-1
没有被评估?
让我们尝试解决这个问题:
natural(1).
natural(X) :-
Y is X-1,
natural(Y).
现在,natural(5)
按预期工作
但是,如果我使用natural(X)
我得到X=1;例外:参数没有充分实例化(Y是X-1)
好吧,我想问题是我们试图评估那些可能没有价值的东西
如果我尝试使用Y=X-1
我们返回到第一个问题Y==X-1
返回false
我发现唯一可行的解决方案是切换行和定义顺序:
natural(1).
natural(X) :-
natural(Y),
X is Y+1.
将最后一行更改为=
将给出“+1+1…”结果<代码>=
只是失败了
此解决方案在生成X=1时非常有效;X=2代码>,但当我使用它作为检查(natural(5)
)时,它的顺序是“0,(0,1),(0,1,2),(0,1,2,3),…”。是的,我得到了正确的结果,但这条路很长,不是我想象的那样。
如果我没有在以前的解决方案中看到更快的检查自然(5)的方法,我会停止在这里
所以,我错过了创建此规则的更好方法吗?
我想一种方法是将“真/假”查询与生成器查询分开。。。但是,有没有一种方法可以使其“如果可能的话进行评估”,即仅将常量与has变量分开var(X-1)
在某种程度上是错误的…通过使用succ/2
处理自然现象通常会有很大的改进<正如您所发现的,Prolog需要代码>is/2
,以计算算术表达式,但它有一个单一的实例化模式:-Number is+Expr
。如果没有约束条件,那么拥有一个完全开放的模式,例如?Number is?Expr
,将是完全疯狂的
另一方面,succ/2
有两种模式:succ(+Pred,-succ)
和succ(-Pred,+succ)
。也就是说:suc(X,3)
unifies X=2和suc(2,X)
unifies X=3。尽管成功(X,Y)仍然是一个错误。但是,您可以使用succ/2
为natural/1
构建解决方案,但需要注意:
natural(1).
natural(X) :- natural(X0), succ(X0, X).
从逻辑上讲,这应该与such(X0,X)、natural(X0)相同,但Prolog不是逻辑,它有一个求值顺序。这个技巧基本上会迫使你要求X是否是自然的,从X-1开始,立即转到X-2,然后向下,直到它达到1,然后它就可以备份并开始成功。如果您提供负数,它会立即失败,因为succ/2
负数失败。这两种方式都适用,但存在一个严重的问题:
?- natural(X).
X = 1 ;
X = 2 ;
X = 3 ;
....
?- natural(5).
true ;
^CAction (h for help) ? abort
是的,如果我们在提供值后请求第二个结果,我们将得到一个无限循环。Prolog开始尝试找出5是否在5之后再次出现
避免该问题的一个简单解决方案是在/3之间使用:
natural(X) :- between(1, inf, X).
?- natural(X).
X = 1 ;
X = 2 ;
X = 3 ;
...
?- natural(5).
true.
没有循环。这将是我首选的解决方案
除了var/1
和nonvar/1
之外,还有ground/1
,它可以区分有变量的术语和没有变量的术语。你可以用它来区分(一边)5,3-1等和另一边的X,X-1。根据我的经验,像这样的情况通常会导致眼泪和向后的正确性问题,但在极端情况下,这可能是有道理的
此时,您可能会对Prolog的逻辑感到有点不高兴。标准体系的算法令人失望。但clpfd功能更强大、更灵活,许多人建议您首先了解这一点,因为它更擅长生成解决方案(is/2
确实无法生成,但使用clpfd标记可以)。根据我的经验,succ/2
与Peano算法非常接近,整数乱来通常是可以的,但是对于任何严重的事情,你都会想使用clpfd。在-
、+
和中的意味着什么?
数字是+Expr
和数字是?Expr
?喜欢你的散文。Thanks@NooneAtAll这些标记告诉您是否需要提供参数(也称为输入参数)——这是+
——或者谓词是否将变量绑定为输出参数——这是-
。?
表示无论参数是否实例化,谓词都有效。?
实例化模式对于这样的谓词很常见,谓词可以在其中生成或检查参数。@谢谢!我所知道的Prolog的85%都归功于你!“通过使用……库(
)
首先使用定义自然数,处理自然数的能力通常会大大提高。在它里面,一切都是自然的,与(is)/2
相比,它是非常困难和不完整的。然后,使用库(clpfd)
,这更自然。想想:X#>=0
。
natural(X) :- between(1, inf, X).
?- natural(X).
X = 1 ;
X = 2 ;
X = 3 ;
...
?- natural(5).
true.