【问题标题】:What's correct way to make natural number rule in prolog?在prolog中制作自然数规则的正确方法是什么?
【发布时间】:2019-12-04 02:50:40
【问题描述】:

我想我在理解 prolog 方面有一些更大的问题,但由于我无法完全表述它,所以我专注于单个问题

我想创建一个规则 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) 的更快方法,我会在这里停下来。


那么,我错过了创建此规则的更好方法吗?

我想一种方法是将“真/假”查询与生成器查询分开......但是有没有办法让它“评估是否可能评估”,即将唯一常量与有变量分开? var(X-1) 在某种程度上是错误的......

【问题讨论】:

  • 首先使用successor-arithmetics 来定义自然数。在里面,一切都是自然的,(is)/2 是非常困难和不完整的。然后,使用library(clpfd),更加自然。想想:X #>= 0.

标签: prolog


【解决方案1】:

使用succ/2 通常可以显着改善处理自然的情况。正如您所发现的,is/2 是 Prolog 评估算术表达式所必需的,但它只有一个实例化模式:-Number is +Expr。没有约束,如果有一个完全开放的模式,比如?Number is ?Expr,那将是完全疯狂的。

另一方面,succ/2 有两种模式:succ(+Pred, -Succ)succ(-Pred, +Succ)。也就是说:succ(X, 3) 统一 X = 2 和 succ(2, X) 统一 X = 3。尽管 succ(X, Y) 仍然是一个错误。但是,您可以使用succ/2 构建natural/1 的解决方案,但需要注意的是:

natural(1).
natural(X) :- natural(X0), succ(X0, X).

从逻辑上讲,这应该与succ(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 之后再次出现。

避免该问题的简单解决方案是使用between/3

natural(X) :- between(1, inf, X).

?- natural(X).
X = 1 ;
X = 2 ;
X = 3 ;
...

?- natural(5).
true.

没有循环。这将是我的首选解决方案。

除了var/1nonvar/1之外,还有ground/1,可以区分有变量的项和没有变量的项。您可以使用它来区分(一侧)5、3-1 等和另一侧的 X、X-1。根据我的经验,像这样拆分案例通常会导致流泪和反向正确性的麻烦,但在极端情况下可能是有必要的。

此时您可能对 Prolog 的逻辑感到有些不快。标准系统的算法令人失望。但是 clpfd 更加强大和灵活,很多人建议你先学习它,因为它更擅长生成解决方案(is/2 确实无法生成,但使用 clpfd 标记可以)。根据我的经验,succ/2 与 Peano 算术非常接近,因此整数混乱通常是可以的,但对于任何严重的事情,您都需要使用 clpfd。

【讨论】:

  • -+?-Number is +Expr?Number is ?Expr 中是什么意思?
  • 爱你的散文。谢谢
  • @NooneAtAll 这些标记告诉你是否需要提供参数(也称为输入参数)——这是+——或者谓词是否会将变量绑定为输出参数——这是-? 表示无论参数是否被实例化,谓词都有效。 ? 实例化模式对于这样的谓词很常见,谓词可以生成或检查参数。
  • @CapelliC 谢谢!我对 Prolog 的了解 85% 都归功于你!
  • “通过使用...通常可以大大改善处理自然的情况”library(clpfd)
【解决方案2】:

您可以通过这种方式检查数字是否自然:

nat(0).
nat(s(X)) :-
    nat(X).

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-18
    • 2013-12-21
    • 2019-03-09
    • 2019-05-07
    • 1970-01-01
    • 1970-01-01
    • 2020-09-14
    • 1970-01-01
    相关资源
    最近更新 更多