我正在尝试在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 :(整数* Z,整数U)程序(i,o)。
我无法将其声明为非术语,因为它会导致整个表单出现问题。你能帮助我/暗示如何使它成为一个程序吗?我想我必须在某个地方进行切割,但到目前为止我的尝试都失败了。
P.S。我正在使用Visual Prolog 7.4。
编辑:在尝试将两个规则组合成一个或使用累加器的替代方案之后,我现在得到谓词是'确定'而不是过程。根据我的Prolog指南,这意味着谓词现在没有多个解决方案,而是有机会失败。基本上我到目前为止所做的所有代码变化都让我陷入了'确定'。
答案 0 :(得分:1)
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).
答案 1 :(得分:1)
问题是Prolog看到了你的第二和第三条规则之间的选择点。换句话说,你,人类,知道X > M
和M >= 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).