我无法弄清楚为什么这种情况会不断变回虚假。我可以计算元素的数量" e"如果我调用另一个函数,在奇数位置的列表中,但我想以更干净和紧凑的方式进行。这是代码:
count(_,[],0).
count(E,[E,_|T],C) :-
count(E,T,D),
C is D+1.
count(E,[H,_|T],C) :-
E\=H,
count(E,T,C).
答案 0 :(得分:3)
@ Sergey的回答是这样的。但是你可能想知道如何自己找出这样的问题。 Prolog实际上可以帮助您完全理解您的Prolog程序。远远超过其他语言能够解释自己。方法如下:
你的程序几乎是一个纯粹的,单调的程序。 (\=)/2
除外,dif/2
或iso_dif/2
应替换count(_,[],0).
count(E,[E,_|T],C) :-
count(E,T,D),
C is D+1.
count(E,[H,_|T],C) :-
dif(E,H), % replaces E \= H
count(E,T,C).
。请参阅this answer why。
false
您抱怨您的计划“不断”返回true
。这是真的吗?您考虑过哪些测试用例?有没有办法证明这个?在传统的,价值导向的编程语言 1 中,答案是您需要求助于某种分析器。但是没有办法在语言中证明它。也许你很幸运能找到count/3
的测试用例。也许不是。
Prolog不是这样!在这里,您可以始终提供一个真实的查询,前提是某些测试用例是真的 2 。你不需要做任何思考(好吧,假装你在想)。只需为每个参数使用一个不同的新变量。所以,考虑到你的谓词?- count(E, Xs, M).
, aah ,让我想一想,请停止这种嘈杂的打字,我必须理解它( feign-fake-feign ), ....它是:
| ?- count(E, Xs, N).
Xs = [],
N = 0 ? ;
Xs = [E,_A],
N = 1 ? ;
Xs = [E,_A,E,_B],
N = 2 ? ;
Xs = [E,_A,E,_B,E,_C],
N = 3 ? ;
Xs = [E,_A,E,_B,E,_C,E,_D],
N = 4 ? ...
因为,如果有任何其他查询成功,它将是此查询的实例。因此,它比这个更具体。并且由于单调性,更通用的查询也必须是真实的。并且,我们现在得到了大量的反例,反例是在银盘上,呃,顶级外壳:
count(1,[1,1],1)
所以你抱怨你的谓词是假的,但我们到目前为止收到的5个答案是真的。这些答案包含无数多个解决方案。要获得所有解决方案,请根据您喜欢的任何基础术语替换所有剩余变量。与count(hi,[hi,u],1)
,| ?- length(Xs, L).
Xs = [],
L = 0 ? ;
Xs = [_A],
L = 1 ? ;
Xs = [_A,_B],
L = 2 ? ;
Xs = [_A,_B,_C],
L = 3 ? ;
Xs = [_A,_B,_C,_D],
L = 4 ? ;
Xs = [_A,_B,_C,_D,_E],
L = 5 ?
等
这些都是答案/解决方案吗?如果我们的计算资源没有用尽,Prolog会列举所有这些吗?想想如何枚举所有整数:
0,1,2,3,... -3,-2,-1。
嗯,对于我们有限的生命,它不会那样工作。我们必须开始
0,1,-1,2,-2,3,-3,......
所以有一个无限序列是好的,但如果我们运气不好,我们可能会有一些“落后”的值。
但我们并不是运气不好!在某些情况下,我们会得到很好的无限序列。想一想:
| ?- length(Xs, L), count(E, Xs, N).
Xs = [],
L = 0,
N = 0 ? ;
Xs = [E,_A],
L = 2,
N = 1 ? ;
Xs = [_A,_B],
L = 2,
N = 0,
prolog:dif(E,_A) ? ;
Xs = [E,_A,E,_B],
L = 4,
N = 2 ? ;
Xs = [E,_A,_B,_C],
L = 4,
N = 1,
prolog:dif(E,_B) ? ...
现在,结合我们的原始查询:
L
这些都是答案,按列表长度排序。一旦我们看到L
的价值增加,我们就知道已经列出了它以下的所有长度!
让我们看一下:-
的值!它们是0,2,2,4,4,4,4,6 ......奇数长度在哪里?显然他们失踪了。因此你的程序太专业了。也许从尽可能小的例子开始......
另一种理解问题的方法是从右到左阅读箭头,这正是Xs = []
指向的方向。
从我们知道Xs = [_,_]
的事实来看,我们可以从这两个规则到Xs = [_,_,_,_]
然后count/3
得出结论。因此,只列举偶数长度。
最后,这是写count(_E, [], 0).
count(E, [E|Xs], N0) :-
count1(E, Xs, N1),
N0 is N1+1.
count(E, [X|Xs], N) :-
dif(E, X),
count1(E, Xs, N).
count1(_E, [], 0).
count1(E, [_|Xs], N) :-
count(E, Xs, N).
的另一种方式:
library(clpfd)
啊,我忘了提及也可以使用的{{1}}。见clpfd
1很容易发现面向价值的编程语言:它们的变量在运行时始终是值!
2某些限制适用: 实际上,这只是纯粹的单调程序中的情况,这就是我首先坚持该属性的原因。然后,结果可能会被非终止或错误所掩盖。
答案 1 :(得分:2)
如果您的Prolog系统支持clpfd,您可以使用以下内容
count/3
的定义。此处显示的代码高效(避免创建无用的选择点)和逻辑纯。
count(E,Xs,C) :-
C #>= 0,
list_item_count(Xs,E,C).
list_item_count([],_,0).
list_item_count([X,_|Xs],E,C) :-
if_(E=X, C0+1 #= C, C0 = C),
list_item_count(Xs,E,C0).
继续进行一些查询:
?- count(1,[1,2,3,1,2],C). % fails: list has wrong length
false.
?- count(1,[1,2,3,1,2,1],C).
C = 1. % succeeds deterministically
?- count(E,[1,2,3,1,2,1],C). % now some more general query!
E = C, C = 1 ; % this must be non-deterministic ...
E = 3, C = 1 ; % ... lest we lose solutions!
E = 2, C = 1 ;
C = 0, dif(E,2), dif(E,3), dif(E,1).
?- length(Xs,_),count(X,Xs,C). % even more general; fair enumeration
C = 0, Xs = [] ;
C = 1, Xs = [X,_A] ;
C = 0, Xs = [_A,_B], dif(X,_A) ;
C = 2, Xs = [X,_A,X,_B] ;
C = 1, Xs = [X,__A,_B,_C], dif(X,_B) ;
C = 1, Xs = [_A,_B, X,_C], dif(X,_A) ;
C = 0, Xs = [_A,_B,_C,_D], dif(X,_A),dif(X,_B) ;
C = 3, Xs = [X,_A, X,_B, X,_C] ;
C = 2, Xs = [X,_A, X,_B,_C,_D], dif(X,_C) ...
答案 2 :(得分:0)
当列表中包含许多元素时,您当前的公式是正确的:
?- count(x, [x, y, x, x], C).
C = 2
但如果元素的数量是奇数,它将会失败。
要纠正此问题,您只需为单元素列表添加几条规则:
count(E,[E],1).
count(E,[H], 0):-
E\=H.
现在它适用于具有奇数个元素的列表:
?- count(x, [x, y, x, x, x], C).
C = 3
?- count(y, [x, y, x, x, x], C).
C = 0
?- count(x, [y, y, y, y, x], C).
C = 1