Prolog-参数没有充分实例化

Prolog-参数没有充分实例化,prolog,arguments,clpfd,instantiation-error,Prolog,Arguments,Clpfd,Instantiation Error,我正在写一个小程序,计算列表中有多少元素不是数字。 这是我的密码: not_number([],0). not_number([X|T],R):- not(number(X)), R1 is R+1, not_number(T,R1). not_number([_|Tail],Result):- not_number(Tail,Result). 如果我执行这样的代码: ?- not_number([1,2,3,5], R). 我得到R=0(应该是

我正在写一个小程序,计算列表中有多少元素不是数字。 这是我的密码:

not_number([],0).
not_number([X|T],R):- 
    not(number(X)),
    R1 is R+1,  
    not_number(T,R1). 

not_number([_|Tail],Result):-
    not_number(Tail,Result).  
如果我执行这样的代码:

?- not_number([1,2,3,5], R).
我得到R=0(应该是这样的)

但如果我在列表中添加一个字符:

?- not_number([1,2,3,5,a], R).
然后我得到了这个错误:

ERROR: not_number/2: Arguments are not sufficiently instantiated
   Exception: (10) not_number([a], _G247) ? 

有人能解释一下代码的错误吗?我不熟悉prolog。

您的问题是,在这样的算术计算中:

not_number(X, Y) :- not_number(X, Y, 0).
not_number([], Y, Y).
not_number([H|T], Y, Z) :-
    \+ (number(H)), 
    Z1 is Z+1,
    not_number(T, Y, Z1).

not_number([H|T], Y, Z) :-
    number(H),
    not_number(T, Y, Z).
cat(adam).
cat(eve).
A是B

右边(B)的一切都必须是已知的。没有变量

您可以这样做:

not_number(X, Y) :- not_number(X, Y, 0).
not_number([], Y, Y).
not_number([H|T], Y, Z) :-
    \+ (number(H)), 
    Z1 is Z+1,
    not_number(T, Y, Z1).

not_number([H|T], Y, Z) :-
    number(H),
    not_number(T, Y, Z).
cat(adam).
cat(eve).
(现在测试了这段代码,它可以工作了)

第三个参数是累加器。它计算有多少个非数字。当列表为空时,第三个参数与第二个参数统一,并成为正确答案

如果有机会,Prolog将遍历所有可能的路径。如果您这样做:

not_number(X, Y) :- not_number(X, Y, 0).
not_number([], Y, Y).
not_number([H|T], Y, Z) :-
    \+ (number(H)), 
    Z1 is Z+1,
    not_number(T, Y, Z1).

not_number([H|T], Y, Z) :-
    number(H),
    not_number(T, Y, Z).
cat(adam).
cat(eve).
然后问:

?- cat(X).
你可以得到两个答案:X=亚当和X=夏娃。 它也适用于您的代码:请注意,当列表的标题不是数字时,您仍然可以执行以下操作:

not_number([_|Tail],Result):-
    not_number(Tail,Result).  
这并不是你想要的答案。你必须切断那些你不感兴趣的路线。在这种情况下,我要补充一点

number(Head).
确保仅当列表中的元素不是数字时,才跳过该元素而不将计数器增加1


要强制Prolog查找其他结果,必须按键盘上的“;”(如本例中的亚当和夏娃)。

此类问题的一般解决方案是使用约束

例如,如果您只使用约束,那么您的程序将完全按照预期工作。只需将
(is)/2
替换为
(#=)/2
,即可获得全方位的整数算法:

示例查询及其结果:

?- not_number([1,2,3,5], R). R = 0. ?非_数([1,2,3,5],R)。 R=0。
还请注意,我已将代码更改为使用ISO谓词
(\+)/1
,而不是
not/1
,我正在编写此答案,因为目前为止最好的答案是by。我想让它显示为一个实际的答案

您的代码不起作用,因为您正在执行
R1为R+1
的操作,而
R
not_number([X | t],R)
的情况下没有实例化。你的递归案例有点倒转。您要执行以下操作:

not_number([X|T],R):- 
    not(number(X)),
    not_number(T,R1),
    R is R1+1.

现在,
is的右侧在调用时被实例化。

在我的例子中,而不是
is
我必须使用
=

而不是这个

X is AnotherVariable
我不得不写信

X = AnotherVariable

因为你正在做的
R1是R+1
,而
R
不是[a],R]的情况下没有实例化。你的递归案例有点倒转。你想做的不是数字(T,R1),R是R1+1。也有很好的讨论
?-不是数字([A,A,B],N)。
有一个解决方案,
N=-3
。我觉得不太对头,罪魁祸首<当然,代码>编号/1
,因为它混合了实例化测试和类型测试。解决方法:
函子(X,\u,\u),\+number(X)
而不是
\+number(X)
。或者,更好的是,
如果使用正确的具体化测试谓词,
非常正确。我建议
必须是(nonvar,X)
。现在可以讨论这一点,因为OP报告的基本问题是通过使用声明性算法解决的。对,我没有注意到实际问题,因为我没有注意到这两个代码有多么相似。