28

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

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 (应该是这样)

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) ? 

有人可以解释代码有什么问题吗?我是序言的新手。

4

4 回答 4

31

我正在写这个答案,因为最好的答案是在lurker的评论中。我想让它显示为实际答案。

您的代码不起作用,因为您正在做R1 is R+1whenR没有在 case 中实例化not_number([X|T], R)。您的递归案例有点倒退。你想这样做:

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

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

于 2015-12-14T13:00:54.830 回答
4

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

甲是乙

右侧 (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).

(现在测试了这段代码,它可以工作)。

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

如果有机会,Prolog 将走遍所有可能的路线。如果你做这样的事情:

cat(adam).
cat(eve).

然后问:

?- cat(X).

你可以得到两个答案:X = adam 和 X = eve。它也适用于您的代码:请注意,当列表的头部不是数字时,您仍然可以这样做:

not_number([_|Tail],Result):-
    not_number(Tail,Result).  

这没有给出你想要的答案。你必须切断你不感兴趣的路线。在这种情况下,我会添加

number(Head).

确保我们跳过列表中的一个元素而不将计数器增加 1,仅当该元素不是数字时。

要强制 Prolog 查找其他结果,您必须按“;” 在你的键盘上(就像这个亚当和夏娃的例子)。

于 2014-05-22T20:36:44.013 回答
2

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

例如,如果您只使用约束,您的程序将完全按预期工作。只需替换(is)/2为即可获得适用于所有方向的(#=)/2整数运算:

:- use_module(library(clpfd)).

not_number([],0).
not_number([X|T],R):- 
    \+ number(X),
    R1 #= R+1,  
    not_number(T,R1). 

not_number([_|Tail],Result):-
    not_number(Tail,Result).

示例查询及其结果:

?- not_number([1,2,3,5], R)。
R = 0。

另请注意,我已将代码更改为使用 ISO 谓词(\+)/1而不是not/1.

于 2015-12-02T07:50:14.293 回答
0

在我的情况下,is我不得不使用=

而不是这个

X is AnotherVariable

我不得不写

X = AnotherVariable
于 2020-06-12T13:48:12.923 回答