Prolog:参数没有充分实例化(列表1 + 2 + ... + n的总和)

时间:2017-03-28 18:14:17

标签: list prolog sum instantiation-error

我需要写一个谓词listsum(L, S),如果L是一个从1增加到某个n的自然数列表(即 [1,2,..,n] )。现在我让它适用于listsum(L, <any number larger than 0>)类型的查询,但是当我尝试查询示例listsum([1,2,3], S)时,它说参数没有充分实例化。这是我的代码:

listsum(L,S) :- listsum(L,S,1).
listsum(L, 0, A) :- 
    N is A-1,
    N > 1,
    fromTo(1, N, L). ; true iff L is the list [1,2,...,N]
listsum(L, S, A) :-
    S > 0,
    SA is S-A,
    A1 is A+1,
    listsum(L, SA, A1).

如果有人可以帮我解决如何以两种方式完成这项工作(同样也是L的给定值,查询S),我们非常感激!

提前致谢。

1 个答案:

答案 0 :(得分:1)

当初学者第一次遇到老式的Prolog代码时,这个错误是一个常见的问题。原因是像(is)/2(>)/2这样的谓词不是 真正的关系。相反,它们仅在其参数足够实例化时才起作用。

这引起了很多困惑,特别是在初学者中,从实际的角度来看显然也是非常不幸的。在Prolog中编程时,我们希望从关系的普遍性中受益,而不是从一开始就陷入如此低级别的问题。

针对此类问题的声明性解决方案是约束。对它们的支持在各种Prolog系统之间有所不同。然而,目前,使用最广泛的Prolog系统至少都存在对整数的约束。

要在GNU Prolog中使用它们,只需对代码进行以下直接更改:

  • (is)/2替换为(#=)/2
  • (>)/2替换为(#>)/2

因此,我们获得:

listsum(L,S) :- listsum(L,S,1).

listsum(L, 0, A) :-
    N #= A-1,
    N #> 1,
    fromTo(1, N, L).
listsum(L, S, A) :-
    S #> 0,
    SA #= S-A,
    A1 #= A+1,
    listsum(L, SA, A1).

此外,如果您的Prolog系统提供fromTo/3,我建议numlist/3的以下定义:

fromTo(1, N, Ls) :- numlist(1, N, Ls).

我自己实施numlist/3作为一项简单的练习。

通过这些更改,我们得到:

?- listsum([1,2,3], S).
S = 6 .

因此,至少我们得到了正确的解决方案,现在可以专注于剩余的问题。

例如,查询不会终止普遍,我们可以看到:

?- listsum([1,2,3], S), false.
nontermination

我将此作为练习进行纠正。

请注意,某些Prolog系统要求您导入库以使用声明性整数算法。