count([], 0, 0).
count([X|T], M, N) :- 1 is X, count(T, MRec, NRec),
M is MRec, N is NRec+1.
count([X|T], M, N) :- 0 is X, count(T, MRec, NRec),
M is MRec+1, N is NRec.
control_number(L) :- count_digit(L, M, N), 2 is M, 3 is N.
?- control_number([1,1,0,0,1]).
ERROR: count_number/3: Undefined procedure: count/3
各位大家好,我需要帮助。此代码必须递归地提供两个单独数字的计数。但是,我无法提供递归
有2个参数。我猜MRec
和NRec
无论如何都无效。
任何帮助将不胜感激。谢谢你......
答案 0 :(得分:3)
这是一个更惯用的重写:
count_digits([], 0, 0).
count_digits([1|T], M, N) :-
count_digits(T, M, NRec),
N is NRec+1.
count_digits([0|T], M, N) :-
count_digits(T, MRec, N),
M is MRec+1.
control_number(L) :-
count_digits(L, 2, 3).
使用library(clpfd)
可以大大改善这一点。也许其他人会回答。
答案 1 :(得分:3)
正如@false已经指出的那样,这个谓词非常适合clpfd。除此之外,我添加了约束(标记为% <-
)以确保M
和N
在递归情况下大于0
,因此Prolog不会继续搜索解决方案一旦这些变量减少到0
。
:- use_module(library(clpfd)).
count_digits([], 0, 0).
count_digits([1|T], M, N) :-
N #> 0, % <-
NRec #= N-1,
count_digits(T, M, NRec).
count_digits([0|T], M, N) :-
M #> 0, % <-
MRec #= M-1,
count_digits(T, MRec, N).
通过这些微小修改,您已经可以通过多种方式使用count_digits / 3。例如,要求所有列表包含2个0
和3个1
&#39>:
?- count_digits(L,2,3).
L = [1,1,1,0,0] ? ;
L = [1,1,0,1,0] ? ;
L = [1,1,0,0,1] ? ;
L = [1,0,1,1,0] ? ;
L = [1,0,1,0,1] ? ;
L = [1,0,0,1,1] ? ;
L = [0,1,1,1,0] ? ;
L = [0,1,1,0,1] ? ;
L = [0,1,0,1,1] ? ;
L = [0,0,1,1,1] ? ;
no
或计算给定列表中0
和1
&s的出现次数:
?- count_digits([1,1,0,0,1],M,N).
M = 2,
N = 3
% 1
甚至可以在包含变量的列表中询问0
和1
的数量:
?- count_digits([1,0,X,Y],M,N).
M = X = Y = 1,
N = 3 ? ;
M = N = 2,
X = 1,
Y = 0 ? ;
M = N = 2,
X = 0,
Y = 1 ? ;
M = 3,
N = 1,
X = Y = 0
这已经非常好了,有人可能会对谓词满意。如果您打算像@false所建议的那样将它与control_number / 1一起使用,那当然没问题。然而,在其他一些问题上愚弄它可能是值得的。例如,最常见的查询:M
0
&{39}和N
1
&#39;是哪些列表?
?- count_digits(L,M,N).
L = [],
M = N = 0 ? ;
L = [1],
M = 0,
N = 1 ? ;
L = [1,1],
M = 0,
N = 2 ? ;
L = [1,1,1],
M = 0,
N = 3 ?
...
仅生成仅由1
组成的列表。这是因为第一个递归规则是描述1
作为列表的第一个元素的情况的规则。所以解决方案的顺序是不公平的。以下查询会发生什么甚至可能不那么直观:哪些列表具有相同(但不是固定)的0
&{39}和1
的数量:< / p>
?- count_digits(L,M,M).
L = [],
M = 0 ? ;
有一个答案然后谓词循环。这不是一个理想的财产。关于这个查询的有趣观察:如果在具有固定长度的列表上使用它,结果实际上是预期的:
?- length(L,_), count_digits(L,M,M).
L = [],
M = 0 ? ;
L = [1,0],
M = 1 ? ;
L = [0,1],
M = 1 ? ;
L = [1,1,0,0],
M = 2 ? ;
L = [1,0,1,0],
M = 2 ? ;
...
将此想法应用于先前的查询会产生对结果的公平排序:
?- length(L,_), count_digits(L,M,N).
L = [],
M = N = 0 ? ;
L = [1],
M = 0,
N = 1 ? ;
L = [0],
M = 1,
N = 0 ? ;
L = [1,1],
M = 0,
N = 2 ? ;
L = [1,0],
M = N = 1 ? ;
...
在不必为辅助目标添加前缀的情况下获得这些结果肯定会很好。再仔细看一下count_digits / 3所描述的关系,另一个观察就会出现:如果有M
0
&{39}和N
1
&# 39; s列表的长度实际上是固定的,即M
+ N
。要将这些观察结果用于工作,可以将count_digits / 3重命名为list_0s_1s / 3,并将count_digits / 3重新定义为具有以下约束的调用谓词:
:- use_module(library(clpfd)).
count_digits(L,M,N) :-
X #= M+N,
length(L,X), % L is of length M+N
list_0s_1s(L,M,N).
list_0s_1s([], 0, 0).
list_0s_1s([1|T], M, N) :-
N #> 0,
NRec #= N-1,
list_0s_1s(T, M, NRec).
list_0s_1s([0|T], M, N) :-
M #> 0,
MRec #= M-1,
list_0s_1s(T, MRec, N).
上面的前三个查询产生与以前相同的结果,但这两个查询现在以公平的顺序生成结果而没有循环:
?- count_digits(L,M,N).
L = [],
M = N = 0 ? ;
L = [1],
M = 0,
N = 1 ? ;
L = [0],
M = 1,
N = 0 ? ;
L = [1,1],
M = 0,
N = 2 ? ;
L = [1,0],
M = N = 1 ?
...
?- count_digits(L,M,M).
L = [],
M = 0 ? ;
L = [1,0],
M = 1 ? ;
L = [0,1],
M = 1 ? ;
L = [1,1,0,0],
M = 2 ? ;
L = [1,0,1,0],
M = 2 ?
...
关于谓词control_number / 1的最后两个注释:首先,如果你使用的是/ 2,请确保使用它如下:
?- M is 2.
M = 2
% 1
而不是(在control_number / 1的定义中使用):
?- 2 is M.
ERROR!!
INSTANTIATION ERROR- in arithmetic: expected bound value
% 1
其次,如果您打算使用类似control_number / 1的谓词来调用count_digits / 3,请不要在之后设置M is 2
和N is 3
之类的目标count_digits / 3的实际调用。这样你就会要求count_digits(L,M,N)
的所有解决方案,其中包含无限多的解决方案,然后在后续目标中过滤掉满足约束的解决方案(M is 2
和N is 3
)。通过这种目标排序,您可以确保在生成有限数量的解决方案后control_number / 1不会终止,因为第一个目标会产生无限多个解决方案候选者,这些目标随后会根据您的约束而失败。相反,首先放置这些约束,或者将它们直接作为参数放入@false发布的目标中。
答案 2 :(得分:0)
累积参数是要走的路(你需要一个辅助谓词来初始化这些参数):
count(List,C0,C1) :-
count_aux(List,C0,C1,0,0).
count_aux([],C0,C1,C0,C1).
count_aux([0|Rest],C0,C1,PartialC0,PartialC1) :-
IncC0 is PartialC0+1,
!,
count_aux(Rest,C0,C1,IncC0,PartialC1).
count_aux([1|Rest],C0,C1,PartialC0,PartialC1) :-
IncC1 is PartialC1+1,
!,
count_aux(Rest,C0,C1,PartialC0,IncC1).
count_aux([_|Rest],C0,C1,PartialC0,PartialC1) :-
count_aux(Rest,C0,C1,PartialC0,PartialC1).
注意:
示例:
?- count([1,1,0,0,0,k],A,B).
A = 3,
B = 2.