我需要写一个谓词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),我们非常感激!
提前致谢。
答案 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系统要求您导入库以使用声明性整数算法。