我想我在理解序言时还存在更大的问题,但是由于我无法完全表述,所以我将重点放在单个问题上
我想创建一个规则natural(X)
,如果X
是1,2,3,4,...
更重要的是,我都希望:natural(5)
是真实的, natural(X)
是输出X=1; X=2; ...
所以,我解释规则如下(伪):
natural(1) must be true
natural(X) is true if natural(X-1) is true
或者,在序言方面:
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; Exception: Arguments not sufficiently instantiated (Y is X-1)
好吧,我想问题是我们试图评估可能还没有价值的东西
如果我尝试使用Y = X-1
,我们将回到第一个问题。 Y == X-1
返回false
我发现唯一可行的解决方案是切换行和定义顺序:
natural(1).
natural(X) :-
natural(Y),
X is Y+1.
将最后一行更改为=
会得到“ + 1 + 1 + 1 ...”结果。 ==
失败了。
此解决方案在生成X=1; X=2; ...
时效果很好,但是当我将其用作检查(natural(5)
)时,它会显示为“ 0,(0,1),(0,1,2), (0,1,2,3),...“顺序。是的,我得到了正确的结果,但是那条路很长,而不是我想像的那样。
如果在以前的解决方案中没有看到检查natural(5)的更快方法,我会在这里停止。
那么,我错过了哪种更好的创建此规则的方法?
我猜一种方法是将“ true / false”查询与生成器查询分开...但是有没有一种方法可以使其“可能评估的话进行评估”,即从has变量中分离唯一常量? var(X-1)
某种程度上是假的...
答案 0 :(得分:2)
使用APIManager.callRequest(url: "someURL", type: Model.self)
通常可以大大改善自然交易。正如您所发现的,Prolog需要 succ/2
来评估算术表达式,但是它具有单个实例化模式:is/2
。没有限制,拥有-Number is +Expr
之类的完全开放的模式将是完全的疯狂。
?Number is ?Expr
具有两种模式:succ/2
和succ(+Pred, -Succ)
。举例来说:succ(-Pred, +Succ)
统一X = 2,而succ(X, 3)
统一X =3。尽管succ(2, X)
仍然是错误。但是,您可以使用succ(X, Y)
构建natural/1
的解决方案,但要注意:
succ/2
从逻辑上讲,这应该与natural(1).
natural(X) :- natural(X0), succ(X0, X).
相同,但是Prolog不是逻辑,它具有评估顺序。该技巧基本上会强制您要求X是否自然地从X-1开始,立即转到X-2,然后向下直到X达到1,然后它可以备份并开始成功。如果提供负数,则它会立即失败,因为succ(X0, X), natural(X0)
的负数将失败。这可以通过您所需的两种方式工作,但是有一个令人讨厌的问题:
succ/2
是的,如果在提供值之后要求第二个结果,则会出现无限循环。 Prolog尝试找出5之后是否再次出现5。
一个避免问题的简单解决方案是使用?- natural(X).
X = 1 ;
X = 2 ;
X = 3 ;
....
?- natural(5).
true ;
^CAction (h for help) ? abort
:
between/3
无循环。这将是我的首选解决方案。
除natural(X) :- between(1, inf, X).
?- natural(X).
X = 1 ;
X = 2 ;
X = 3 ;
...
?- natural(5).
true.
和var/1
外,还有nonvar/1
,它们可以区分具有变量的术语和不具有变量的术语。您可以使用它来区分(一侧)5、3-1等与另一侧的X,X-1。以我的经验,将这样的情况分开通常会导致眼泪和向后正确性的麻烦,但在极端情况下,这是有必要的。
在这一点上,您可能对Prolog的逻辑感到有些不适。标准系统的算法令人失望。但是clpfd更加强大和灵活,许多人建议您首先学习它,因为它更擅长生成解决方案(ground/1
确实无法生成,但是可以使用clpfd进行标记)。根据我的经验,is/2
与Peano算术足够接近,以至于整数混乱通常是可以的,但是对于任何严重的问题,您都希望使用clpfd。