List 只计算数字和字母列表中的数字

List 只计算数字和字母列表中的数字,list,count,numbers,prolog,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. 是我得到的,但它显然给了我列表中的每个元素。我不知道如何以及在何处放置“仅计数数字”。考虑使用内置谓词(例如在SWI Prolo

我对Prolog还不熟悉,我自己似乎无法找到这个问题的答案

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

getnumbers([1, 2, c, h, 4], X).
你应该给我:

X=3

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

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

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


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

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


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

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

/1它是您要查找的谓词


另请参见construct,以便在递归子句中使用。

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

/1它是您要查找的谓词


另请参见要在递归子句中使用的构造。

与往常一样,当您使用列表(和SWI Prolog)时,您可以使用在此处找到的模块lambda.pl:


通常,当您使用列表(和SWI Prolog)时,可以使用以下模块lambda.pl:


这使用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).

这使用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).

与这类问题相关的一个常见的prolog习惯用法是首先为公共消费定义谓词,并让它调用“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\u numbers\u in\u list/3
是尾部递归的。这不是:

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

与这类问题相关的一个常见的prolog习惯用法是首先为公共消费定义谓词,并让它调用“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\u numbers\u in\u list/3
是尾部递归的。这不是:

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

保持逻辑上的纯粹,这很容易:使用元谓词 与具体化的类型测试谓词
number\u t/2
(缩写为
number\u truth/2
):

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

?- tcount(number_t,[1,2,c,h,4],N). N = 3. % succeeds deterministically
保持逻辑上的纯粹,这很容易:使用元谓词 与具体化的类型测试谓词
number\u t/2
(缩写为
number\u truth/2
):

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

?- tcount(number_t,[1,2,c,h,4],N). N = 3. % succeeds deterministically
啊,我明白了,这非常有效。谢谢,但是如果我想避免使用内置谓词,你能告诉我正确的方向吗?类似于在现有代码中实现“仅使用数字”。从我所看到的情况来看,您似乎只能在咨询prolog时使用number/1,这是真的吗?啊,我明白了,这非常有效。谢谢,但是如果我想避免使用内置谓词,你能告诉我正确的方向吗?类似于在现有代码中实现“仅使用数字”。据我所见,似乎只有在咨询prolog时才可以使用number/1,是真的吗?如果head是一个数字,第三个子句也会匹配。不理解mat。如果head是一个数字,它将被第二条规则捕获,因此第三条规则永远不会到达,因为3个子句将按照1..2..3的顺序执行,或者我是否遗漏了什么?如果head是一个数字,则第二条规则和第三条规则都适用。多亏了回溯,这两种方法都将被尝试,是的,按照这个顺序。例如,您是否在
?-getnumbers([1])上尝试过该程序。
?我知道可以应用#2和#3,但实际上,通过回溯选择第三条规则的唯一情况是第二条规则失败。。因为数字(H)失败了。getnumbers([1])看起来不错。。跟踪中从未使用第3子句,显示的结果是否正确?Re:解决方案,你是说not(数字(H))应该是第3行吗?(抱歉..我仍然不理解你的观点-你是在理论上说话吗..哪些子句可以被选择,哪些将在这个特定示例中被选择)
?-getnumbers([1],N)
产生两个解决方案:第一个解决方案是正确的(
N=1
)。回溯时(在SWI Prolog中,按空格键获取其他解决方案),第三个子句将被尝试并应用,您将得到一个额外的、不正确的解决方案(
N=0
)。是的,在第三个子句中添加
\+数字(H)
(注意
(\+)/1
是ISO,而
不是/1
是ISO)是纠正这一点的一种方法。查看此问题的另一种方法是简单地询问
?-getnumbers([1],0)。
并查看它是否成功