1

我是 Prolog 的新手,我自己似乎无法得到答案。

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

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

应该给我:

X=3

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

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

4

6 回答 6

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).
于 2013-04-21T17:57:19.530 回答
1

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

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

于 2013-04-21T15:56:37.010 回答
1

保持逻辑纯洁,这很容易:将元谓词 tcount/3与具体的类型测试谓词number_t/2(缩写number_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. % 确定性成功

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

?- tcount(number_t,[A,B,C,D,E],N), A=1 , B=2 , C=c, D=h, E=4N = 3,A = 1,B = 2,C = c,D = h,E = 4;% 成功,但留下选择点
错误的。

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

?- 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)).
于 2015-06-16T03:07:12.873 回答
0

这使用 Prolog 与 number/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).
于 2013-04-22T13:32:59.663 回答
0

当然,你必须检查一个元素的类型,看它是否满足条件。

number /1 这是您要查找的谓词。

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

于 2013-04-21T15:56:49.317 回答
0

此类问题的一个常见 prolog 习语是首先定义您的谓词以供公共消费,并让它调用一个“工人”谓词。通常它会使用某种累加器。对于您的问题,公共消费谓词类似于:

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.
于 2013-04-22T21:25:09.457 回答