Aggregate solution over multiple facts

前端 未结 2 714
你的背包
你的背包 2021-01-26 11:38

Trying to create a predicate (timePeriod/2) that calculates the time period between two dates for a specific fact. I\'ve managed to do this by myself, but face issu

相关标签:
2条回答
  • 2021-01-26 12:03

    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.
    
    0 讨论(0)
  • 2021-01-26 12:15

    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).
    
    0 讨论(0)
提交回复
热议问题