2016-11-17 85 views
1

的序言数数我学习序言,我想指望在一个列表中的特定元素occurence。元素错误

所以这里是代码 -

count(_, [], _) := !. 

count(El, [El|T], N) :- 
    N1 is N + 1, 
    count(El, T, N1). 

count(El, [_|T], N) :- 
    count(El, T, N). 

check(List1, List2) :- 
    count(3, List1, M), 
    count(2, List2, N), 
    M is N. 

所以基本上我想传递给控制台检查([3,4,3],[2,3,4,5,2]),以及它应该返回true,因为list1中3的出现次数与list2中出现次数2相同。而是它抛出我 -

Arguments are not sufficiently instantiated. 
Exception: (10) _G1383 is _L155+1 ? creep 
Exception: (9) count(3, [3, 4, 2], _G1385) ? creep 
Exception: (8) count(3, [2, 3, 4, 2], _G1385) ? creep 
Exception: (7) check([2, 3, 4, 2], [2, 3, 4]) ? creep 

什么是这个原因,我该怎么解决呢?我检查了所有的论坛,并在任何地方写入这个应该工作。这是一些与版本相关的东西,还是真的我在这里错过了一些东西?

编辑:使用SWI-Prolog的。编号2:

明白了,谢谢!

代码:被称为

count(_, [], 0) :- !. 

count(El, [El|T], N) :- 
    count(El, T, N1), 
    N #= N1 + 1. 

count(El, [Y|T], N) :- 
    El \= Y, 
    count(El, T, N). 

check(List1, List2) :- 
    count(3, List1, M), 
    count(2, List2, N), 
    M #= N. 
+1

请参阅[本](http://stackoverflow.com/a/28971616/772868)以获得纯粹而高效的解决方案。 – false

+1

您至少需要'dif(E1,Y)'代替'E1 \ = Y', – false

回答

1

您正在使用谓词moded,因为它们只能在非常特殊的情况下使用。特别是,(is)/2不能用作关系,因为您在这里需要它。

解决此问题的一种方法是使用更一般的谓词来代替。例如,推理,当超过整数,可以考虑使用在各个方向的Prolog的系统CLP(FD)的约束,它的工作。

例如,GNU Prolog的,可以使错误消失,如果你只是通过(#=)/2更换(is)/2

 
count(_, [], _). 

count(El, [El|T], N) :- 
    N1 #= N + 1, 
    count(El, T, N1). 

count(El, [_|T], N) :- 
    count(El, T, N). 

check(List1, List2) :- 
    count(3, List1, M), 
    count(2, List2, N), 
    M #= N. 

现在,我们得到:

 
?- count(3, [3, 4, 2], C). 
C+1#=_1204 ; 
true ; 
false. 

(或根据在你的Prolog系统上,等价的答案)。

为什么?很明显,该计划有点不妥。

我离开发现的错误作为一个练习。提示:M #= N看起来很可疑:这是真的当且仅当M等于 到   N ...

+0

我想SWI-prolog中的#=计为注释,需要检查它。编辑更新的答案,我正在使用的prolog。 – user980952

+1

在SICStus Prolog,YAP和SWI中,您需要在开始处添加': - use_module(库(clpfd))。'以使用声明性整数算术。 – mat

2

这是伟大的,你得到了它现在的工作,通过使用声明算术!

我对你获得的溶液,即一些小的补充意见:

 
count(_, [], 0) :- !. 

count(El, [El|T], N) :- 
    count(El, T, N1), 
    N #= N1 + 1. 

count(El, [Y|T], N) :- 
    El \= Y, 
    count(El, T, N). 

check(List1, List2) :- 
    count(3, List1, M), 
    count(2, List2, N), 
    M #= N. 

首先,请注意check/2在代码中使用无门,所以我忽略它的定义如下。

最一般的查询

当我回顾Prolog的代码,我一无所知,我总是尝试最一般的查询首先,所有的参数都是变量。理想情况下,答案告诉我什么解决方案看起来像一般

例如,你的情况:

 
?- count(E, Ls, C). 
Ls = [], 
C = 0. 

这—错误—表明,只有一个单一的解决的谓语!这显然不是有意的。

因此,作为第一步,我建议你删除!/0这个代码更改为:

 
count(_, [], 0). 

count(El, [El|T], N) :- 
    count(El, T, N1), 
    N #= N1 + 1. 

count(El, [Y|T], N) :- 
    El \= Y, 
    count(El, T, N). 

随着这一变化应用,我们得到:

 
?- count(E, Ls, C). 
Ls = [], 
C = 0 ; 
Ls = [E], 
C = 1 ; 
Ls = [E, E], 
C = 2 ; 
Ls = [E, E, E], 
C = 3 . 

这看起来多少更好:我们现在得到几个有效答案

终止

多少答案可能这个谓词的收益呢?特别是,只有有限很多答案?如果是的话,我们希望下面的查询终止

 
?- count(E, Ls, C), false. 

你可以尝试一下,看看它实际上结束(至少不是很快)。这是一个好的迹象,因为从正确执行count/3,我们期待非终止在最一般的情况下!

完整性

理想情况下,我们希望谓词是完整:它不应该省略有效的答案。

例如:

 
?- count(E, [X,Y,Z], C). 
E = X, X = Y, Y = Z, 
C = 3; 
false. 

难道这些真的所有解决方案?我不这么认为!当然,有不同于  [E,E,E]的长度为  3的列表。

而且,事实上,你的程序也“知道”他们在某种意义上:

 
?- count(E, [1,2,3], C). 
E = C, C = 1 ; 
false. 

但同样,这些肯定不是所有情况下E不同 from   1的答案在哪里?

您正面临这些问题,因为您使用的是非单调的(\=)/2  谓词。这有几个很难理解的属性,特别是如果你目前只开始学习  Prolog。例如:

 
?- X \= Y, X-Y = a-b. 
false. 

?- X-Y = a-b, X \= Y. 
X = a, 
Y = b. 

我建议使用dif/2,而不是来表示两个术语不同,获得以下版本:

 
count(_, [], 0). 

count(El, [El|T], N) :- 
    count(El, T, N1), 
    N #= N1 + 1. 

count(El, [Y|T], N) :- 
    dif(El, Y), 
    count(El, T, N). 

威特这个版本中,我们得到:

 
?- count(E, [X,Y,Z], C). 
E = X, X = Y, Y = Z, 
C = 3 ; 
E = X, X = Y, 
C = 2, 
dif(Y, Z) ; 
E = X, X = Z, 
C = 2, 
dif(Z, Y); 
etc. 

而且,特别是:

 
?- count(E, [1,2,3], C). 
E = C, C = 1 ; 
E = 2, 
C = 1 ; 
E = 3, 
C = 1 ; 
C = 0, 
dif(E, 3), 
dif(E, 2), 
dif(E, 1). 

这包括所有情况下可能出现!

博览会枚举

因为该谓词单调,我们可以用它来迭代深化相当枚举答案。

例如:

 
?- length(Ls, _), count(E, Ls, C). 
Ls = [], 
C = 0 ; 
Ls = [E], 
C = 1 ; 
Ls = [_G588], 
C = 0, 
dif(E, _G588) ; 
Ls = [E, E], 
C = 2 ; 
Ls = [E, _G597], 
C = 1, 
dif(E, _G597) . 
C = 2; 
etc. 

这是相当不错的,并表明我们可以用这个作为一个真正的关系,不仅为计数,同时也为产生

因此,你可以考虑谓词更恰当地描述了这个谓词意味着在 一般。我把这留作练习。

尾递归版本

注意,因为你正在使用谓词,您可以自由重新排序自己的目标,并让你的谓语尾递归,得到以下特性:

 
count(_, [], 0). 
count(El, [El|T], N) :- 
    N #= N1 + 1, 
    count(El, T, N1). 
count(El, [Y|T], N) :- 
    dif(El, Y), 
    count(El, T, N). 

确定性

我们目前仍然有例如:

 
?- count(a, [a,a,a], Cs). 
Cs = 3 ; 
false. 

使用if_/3,可以提高该谓词的决定

 
:- use_module(library(reif)). 

count(_, [], 0). 
count(E, [L|Ls], N) :- 
     if_(E=L, N #= N1 + 1, N #= N1), 
     count(E, Ls, N1). 

这使你的断言至少适合建立索引。在这种情况下是否改进确定性取决于您的Prolog系统的索引机制。