【问题标题】:Prolog issue with max list function: nondeterm vs procedure最大列表功能的 Prolog 问题:nondeterm vs procedure
【发布时间】:2013-11-24 20:23:57
【问题描述】:

我正在尝试在 prolog 中做一个小项目,用户可以输入一个列表,然后计算列表中的平均值、最大值等。

到目前为止一切顺利,但我在编写 max 函数时遇到了问题(在列表中找到最大数)。代码是:

maxN([X],X):-!.
maxN([X|L],X) :- maxN(L,M), X > M.
maxN([X|L],M) :- maxN(L,M), M >= X.

函数本身单独工作,但我收到以下错误消息:

谓词'forma::maxN/2 (i,o)',声明为'procedure',实际上是'nondeterm' forma.pro

这是我在 *.cl 定义中的谓词:

maxN: (integer* Z, integer U) 过程 (i,o)。

我不能将其声明为不确定,因为它会导致我的整个表单出现问题。你能帮我/给一个提示如何使它成为一个程序吗?我在想我必须在某个地方进行削减,但到目前为止我的尝试都失败了。

附:我正在使用 Visual Prolog 7.4。

编辑:在尝试了将两条规则合二为一或使用累加器的替代方案后,我现在知道谓词是“确定”而不是过程。根据我的 Prolog 指南,这意味着谓词现在没有多个解决方案,而是有可能失败。基本上,到目前为止我所做的所有代码变体都让我有了一个“确定”。

【问题讨论】:

  • 你应该在问题中包含方言。
  • 感谢大家的帮助,我通过添加以下内容修复了“确定”问题:maxN([], Max) :- Max=0,!。现在,我知道这在技术上不太正确,但是由于我的程序检查一个空列表(基本上, maxN([], Max) 永远不会被调用,并且只是为了规则的完整性,它可以工作对我来说。谢谢你们的建议,他们让我朝着正确的方向前进!
  • 如果你在第一个参数中传递了列表以外的东西,它仍然会失败。如果您仍想“修复”该问题(我不会),您可以提供另一个 maxN(X, undefined) :- \+ is_list(X). 形式的规则
  • 感谢您的建议!我肯定会补充一点,在用其他语言编写时,我通常对输入非常偏执,但作为 Prolog 新手,我不知道这种“检查”方式。
  • 我不能代表其他人,但我通常很乐意让谓词因意外输入而失败。我认为它利用了 Prolog 的优势,尽管留给您的调试场景是跟踪。话又说回来,不管怎样,你最终还是要追踪。

标签: prolog visual-prolog


【解决方案1】:

问题在于 Prolog 在您的第二条和第三条规则之间看到了一个选择点。换句话说,人类知道X > MM >= X 不可能同时为真,但Prolog 无法推断出这一点。

IMO 最好的办法是用一条规则重新表述这两条规则:

maxN([X], X) :- !.
maxN([X|L], Max) :- 
   maxN(L, M), 
   X > M -> Max = X
          ; Max = M.

这样一来,就不会再有需要修剪的额外选择点了。

按照@CapelliC 的建议,您还可以使用累加器重新表述:

maxN([X|Xs], Max) :- maxN_loop(Xs, X, Max).

maxN_loop([], Max, Max).
maxN_loop([X|Xs], Y, Max) :- 
   X > Y -> maxN_loop(Xs, X, Max)
          ; maxN_loop(Xs, Y, Max).

【讨论】:

  • 谢谢你的意见,丹尼尔,很抱歉没有提到方言!正如你可能看到的,我对 Prolog 的所有东西都有些陌生。
  • 没关系。这是获得帮助的好地方,但我应该提一下,这里没有人特别在 Visual Prolog 方面有丰富的经验。如果您切换到 SWI-Prolog 或 GNU Prolog,您会发现在这里获得帮助会更容易。
  • 啊,谢谢!顺便说一句,我在输入整个回复之前不小心按了 Enter。我的意思是说我对你的建议做了什么:实际上我之前尝试过用一个来改写规则,但后来我得到的不是“nondeterm”,而是 maxN 是“determ”,这也给出了一个错误。据我的 Prolog 指南所说, determ 意味着谓词不会给出多个解决方案,但有一个选项会失败。我尝试了你和 CapelliC 给出的 Acc 建议,但它也让我做出了“决定”。但无论如何,谢谢,你指出了我正确的方向,我会继续解开 Prolog 的奥秘!
【解决方案2】:

抱歉,我不知道您使用的 Prolog 方言,我的建议是尝试在第二个子句后添加一个剪切:

maxN([X|L],X) :- maxN(L,M), X > M, !.

一般来说,我认为可以将递归过程确定性地转换为尾递归。不幸的是,这需要添加一个累加器:

maxN([],A,A).
maxN([X|L],A,M) :- X > A, !, maxN(L,X,M).
maxN([X|L],A,M) :- maxN(L,A,M).

当然,顶级调用应该变成

maxN([F|L],M) :- maxN(L,F,M).

【讨论】:

  • 感谢 CapelliC 的建议!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多