仅计算数字和字母列表中的数字

时间:2013-04-21 15:48:13

标签: list count numbers prolog

我是Prolog的新手,我似乎无法自己解决这个问题。

我想要的是,Prolog在列表中计算所有数字,而不是每个元素。例如:

getnumbers([1, 2, c, h, 4], X).

应该给我:

X=3

getnumbers([], 0).
getnumbers([_ | T], N) :- getnumbers(T, N1), N is N1+1.

我有什么,但它显然给了我列表中的每个元素。我不知道如何以及在何处放置“仅计数”。

6 个答案:

答案 0 :(得分:2)

像往常一样,当您使用列表(和SWI-Prolog)时,您可以使用在那里找到的模块lambda.pl:http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl

:- use_module(library(lambda)).

getnumbers(L, N) :-
    foldl(\X^Y^Z^(number(X)
             ->  Z is Y+1
             ;   Z = Y),
          L, 0, N).

答案 1 :(得分:1)

考虑使用内置谓词(例如在SWI-Prolog中),并检查它们的实现,如果您对如何自己做这件事感兴趣:

include(number, List, Ns), length(Ns, N)

答案 2 :(得分:1)

保持逻辑纯粹,很简单:使用元谓词 tcount/3与改进的类型测试谓词number_t/2number_truth/2的缩写)相配合:

number_t(X,Truth) :- number(X), !, Truth = true.
number_t(X,Truth) :- nonvar(X), !, Truth = false.
number_t(X,true)  :- freeze(X,  number(X)).
number_t(X,false) :- freeze(X,\+number(X)).

让我们运行OP建议的查询:

?- tcount(number_t,[1,2,c,h,4],N).
N = 3.                                       % succeeds deterministically

请注意,这是单调的:延迟变量绑定始终是逻辑上合理的。考虑:

?- tcount(number_t,[A,B,C,D,E],N), A=1, B=2, C=c, D=h, E=4.
N = 3, A = 1, B = 2, C = c, D = h, E = 4 ;   % succeeds, but leaves choice point
false.

最后,让我们看一下以下相当普遍的查询的一些答案:

?- tcount(number_t,[A,B,C],N).
N = 3, freeze(A,  number(A)), freeze(B,  number(B)), freeze(C,  number(C)) ;
N = 2, freeze(A,  number(A)), freeze(B,  number(B)), freeze(C,\+number(C)) ;
N = 2, freeze(A,  number(A)), freeze(B,\+number(B)), freeze(C,  number(C)) ;
N = 1, freeze(A,  number(A)), freeze(B,\+number(B)), freeze(C,\+number(C)) ;
N = 2, freeze(A,\+number(A)), freeze(B,  number(B)), freeze(C,  number(C)) ;
N = 1, freeze(A,\+number(A)), freeze(B,  number(B)), freeze(C,\+number(C)) ;
N = 1, freeze(A,\+number(A)), freeze(B,\+number(B)), freeze(C,  number(C)) ;
N = 0, freeze(A,\+number(A)), freeze(B,\+number(B)), freeze(C,\+number(C)).

答案 3 :(得分:0)

当然,您必须检查元素的类型以确定它是否满足条件。

number / 1这是你正在寻找的谓词。

另请参阅if/then/else构造,以在递归子句中使用。

答案 4 :(得分:0)

这使用Prolog的自然模式与数字/ 1匹配,以及附加条款(下面的3)来处理非数字的情况。

% 1 - base recursion
getnumbers([], 0).

% 2 - will pass ONLY if H is a number
getnumbers([H | T], N) :- 
    number(H),
    getnumbers(T, N1), 
    N is N1+1.

% 3 - if got here, H CANNOT be a number, ignore head, N is unchanged, recurse tail  
getnumbers([_ | T], N) :- 
    getnumbers(T, N).

答案 5 :(得分:0)

这类问题的常见原因是首先为公共消费定义谓词,并让它调用'worker'谓词。通常它会使用某种累加器。对于您的问题,公共消费谓词类似于:

count_numbers( Xs , N ) :-
  count_numbers_in_list( Xs , 0 , N ) .

count_numbers_in_list( [] , N , N ) .
count_numbers_in_list( [X|Xs] , T , N ) :-
  number(X) ,
  T1 is T+1 ,
  count_numbers_in_list( Xs , T1 , N )
  .

您还需要构造递归位,以便它也是尾递归,这意味着递归调用除了参数列表中的数据之外什么都不依赖。这允许编译器在每次调用时重用现有的堆栈帧,因此谓词实际上变为迭代而不是递归。正确的尾递归谓词可以处理无限长度的列表;一个不会在每次递归时分配一个新的堆栈帧并最终炸掉它的堆栈。上面的count_numbers_in_list/3是尾递归的。这不是:

getnumbers([H | T], N) :- 
  number(H),
  getnumbers(T, N1), 
  N is N1+1.