Aggregate solution over multiple facts

我与影子孤独终老i 提交于 2019-12-02 08:42:29

You probably don't quite understand what foreach/3 does. I don't think I fully understand foreach/3 either. I know for sure that it is not the same as say:

for each x in xs:
    do foo(x)

Another thing: "tuples" in Prolog are not what you might expect, coming from a language like Python or Haskell. This: (a,b,c) is actually this: ','(a,','(b,c)). Much better is to use a flat term, the generic form would be triple(a,b,c). For a pair, the idiom is First-Second.

So, you can simplify your call to bagof/3 to this:

?- bagof(From-To, pop_star(Name, Start, End), Ts).
Name = 'Bowie',
Ts = [2008-2010] ;
Name = 'Jackson',
Ts = [1987-1991, 1992-1996] ;
Name = 'Michaels',
Ts = [1996-2000] ;
Name = 'Newcastle',
Ts = [2000-2007].

Once you have a list as above, you need to sum the differences, which would be maybe something like:

periods_total(Ps, T) :-
    maplist(period_length, Ps, Ls),
    sum_list(Ls, T).

period_length(From-To, Length) :-
    Length is To - From + 1.

And then you can query like this:

?- bagof(From-To, pop_star('Jackson', From, To), Ps), periods_total(Ps, T).
Ps = [1987-1991, 1992-1996],
T = 10.

?- bagof(From-To, pop_star(Name, From, To), Ps), periods_total(Ps, T).
Name = 'Bowie',
Ps = [2008-2010],
T = 3 ;
Name = 'Jackson',
Ps = [1987-1991, 1992-1996],
T = 10 ;
Name = 'Michaels',
Ps = [1996-2000],
T = 5 ;
Name = 'Newcastle',
Ps = [2000-2007],
T = 8.

SWI-Prolog has a nice library to handle aggregation: it builds upon standard 'all solutions' predicates like findall/3,setof/3,bagof/3, so you should first grasp the basic of these (as Boris explained in his answer). With the library, a single query solves your problem:

timePeriod(PS,X) :-
    aggregate(sum(P), B^E^(popStar(PS,B,E),P is E-B+1), X).
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!