Prolog - 计算数字的出现次数

use*_*ser 3 prolog

我想写谓词,它可以计算所有遇到的数字:

count(1, [1,0,0,1,0], X).
X = 2.
Run Code Online (Sandbox Code Playgroud)

我试着把它写成:

count(_, [], 0).
count(Num, [H|T], X) :- count(Num, T, X1), Num = H, X is X1 + 1.
Run Code Online (Sandbox Code Playgroud)

为什么不工作呢?

fal*_*lse 7

为什么不工作呢?

Prolog是一种编程语言,通常可以直接回答这个问题.看看我如何从失败的查询开始尝试你的定义:

?- count(1, [1,0,0,1,0], X).
false.

?- count(1, Xs, X).
Xs = [],
X = 0 ;
Xs = [1],
X = 1 ;
Xs = [1, 1],
X = 2 ;
Xs = [1, 1, 1],
X = 3 ...

?- Xs = [_,_,_], count(1, Xs, X).
Xs = [1, 1, 1],
X = 3 ;
false.
Run Code Online (Sandbox Code Playgroud)

所以首先我意识到查询根本不起作用,然后我推广了查询.我用一个变量替换了大名单Xs并说:Prolog,为我填补空白!而Prolog做到了这一点,并准确地向我们揭示了它将成功的案例.

实际上,它仅仅以1的列表成功.这很奇怪.您的定义太受限制 - 它正确计算列表中的1,其中只有1,但所有其他列表都被拒绝.@coder向您展示了如何扩展您的定义.

这是另一个library(reif)用于 SICStus | SWI.或者,请参阅tfilter/3.

count(X, Xs, N) :-
   tfilter(=(X), Xs, Ys),
   length(Ys, N).
Run Code Online (Sandbox Code Playgroud)

定义更符合其他定义的风格:

count(_, [], 0).
count(E, [X|Xs], N0) :-
   if_(E = X, C = 1, C = 0),
   count(E, Xs, N1),
   N0 is N1+C.
Run Code Online (Sandbox Code Playgroud)

现在用于更一般的用途:

四元素列表如何看起来有3倍1?

| ?- length(L, 4), count(1, L, 3).
     L = [1,1,1,_A],
     dif(1,_A)
  ;  L = [1,1,_A,1],
     dif(1,_A)
  ;  L = [1,_A,1,1],
     dif(1,_A)
  ;  L = [_A,1,1,1],
     dif(1,_A)
  ;  false.
Run Code Online (Sandbox Code Playgroud)

所以剩下的元素必须与之不同1.

这是Prolog为我们提供的优良通用性.