Prolog:计算e在奇数位置的列表中出现的次数

时间:2014-11-08 09:01:10

标签: list prolog

我无法弄清楚为什么这种情况会不断变回虚假。我可以计算元素的数量" 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).

3 个答案:

答案 0 :(得分:3)

@ Sergey的回答是这样的。但是你可能想知道如何自己找出这样的问题。 Prolog实际上可以帮助您完全理解您的Prolog程序。远远超过其他语言能够解释自己。方法如下:

使用纯粹,单调的Prolog

你的程序几乎是一个纯粹的,单调的程序。 (\=)/2除外,dif/2iso_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}}。见


精细打印

1很容易发现面向价值的编程语言:它们的变量在运行时始终是值!

2某些限制适用: 实际上,这只是纯粹的单调程序中的情况,这就是我首先坚持该属性的原因。然后,结果可能会被非终止或错误所掩盖。

答案 1 :(得分:2)

如果您的Prolog系统支持,您可以使用以下内容 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