2017-10-20 23 views
2

我想弄清楚如何在count和sum规则上使用递归。如何在Prolog中递归计数和求和

我通常用list,findall和length或findall和sum_list来做,但我不确定这是否是我所有情况下的最佳选择。

这是我的做法与列表:

%person(name, surname, age) 
person('A', 'H', 22). 
person('B', 'G', 24). 
person('C', 'F', 20). 
person('D', 'E', 44). 
person('E', 'D', 45). 
person('F', 'C', 51). 
person('G', 'B', 40). 
person('H', 'A', 51). 

count_person(Total_count) :-   % rule to count how many person are. 
    findall(N, person(N, _, _), List), 
    length(List, Total_count). 

sum_ages(Total_sum) :-     % rule to sum all the ages. 

    findall(Age, person(_, _, Age), List), 
    sum_list(List, Total_sum). 

或在这里:https://swish.swi-prolog.org/p/cswl.pl

我应该怎么做这个使用递归?

回答

1

你应该看一看库(aggregate)。

例如:

count_person(Total_count) :- 
    aggregate(count, A^B^C^person(A,B,C), Total_count). 

或简单的形式(尝试理解上的差异,这是学习基本的有关变量的AA好办法量化

count_person(Total_count) :- 
    aggregate_all(count, person(_,_,_), Total_count). 

图书馆已经成长出于简化SQL中典型聚合函数的实现的必要性(因为Prolog是关系型的):

sum_ages(Total_sum) :- 
    aggregate(sum(Age), A^B^person(A,B,Age), Total_sum). 

您还可以在一个步骤中获得组合聚合。一般容易实现:

ave_ages(Ave) :- 
    aggregate(t(count,sum(Age)), A^B^person(A,B,Age), t(Count,Sum)), Ave is Sum/Count. 

如果要实现使用count_person/1和sum_ages/1的解释将扫描两次目标...

1

我没有一个优雅的解决方案。但随着retractassert您可以控制递归:

:- dynamic([person/3,person1/3]). 

count_person(N) :- 
    count_person(0,N). 

count_person(Acc,N) :- 
    retract(person(A,B,C)), 
    !, 
    assert(person1(A,B,C)), 
    N1 is Acc+1, 
    count_person(N1,N). 
count_person(N,N) :- 
    clean_db. 

clean_db :- 
    retract(person1(A,B,C)), 
    assert(person(A,B,C)), 
    fail. 
clean_db.