基于多个事实的聚合解决方案 [英] Aggregate solution over multiple facts
问题描述
尝试创建一个谓词 (timePeriod/2
) 来计算特定事实的两个日期之间的时间段.我自己设法做到了这一点,但是当同一列表中存在其他答案"时会遇到问题(即更容易用示例解释).
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 issues when 'other answers' exist in the same list (i.e. easier to explain with examples).
我有以下知识库事实;
popStar('Jackson',1987,1991).
popStar('Jackson',1992,1996).
popStar('Michaels',1996,2000).
popStar('Newcastle',2000,2007).
popStar('Bowie',2008,2010).
以下函数计算特定事实的日期之间的时间(如下所示).
And the following function, calculates the time between dates for a specific fact (as per below).
谓词(timePeriod/2)-
timePeriod(PS,X) :-
bagof((Name,Start,End),popStar(Name,Start,End),PSs),X is End-Start+1)
以鲍伊为例;它返回 X=3
(这是正确的).
Using Bowie as an example; it returns X=3
(which is correct).
但是,当列表中存在重复且有多个答案可用时,谓词只会声明假".以事实杰克逊"为例,我希望能够计算两个事实的两个时间段;同时.
However, when there is repetition in the list, with more than one answer available, the predicate just states 'false'. Using the facts 'Jackson' as an example, I want to be able to calculate both of the time periods for both facts; at the same time.
因此,如果谓词适用于两个杰克逊事实,则谓词 timePeriod
将声明 X=10
.
So, if the predicate would work for both of the Jackson facts, the predicate timePeriod
would state X=10
.
如果有人能建议改变什么以使其正常工作,我将不胜感激.
Would really appreciate if anyone could suggest what to change in order for this to work correctly.
谢谢.
推荐答案
你可能不太明白 foreach/3
是做什么的.我也不认为我完全理解 foreach/3
.我确定这与说 不 相同:
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)
另一件事:Prolog 中的元组"不是您所期望的,它来自 Python 或 Haskell 等语言.这:(a,b,c)
实际上是这样的:','(a,','(b,c))
.更好的是使用扁平术语,通用形式是 triple(a,b,c)
.对于一对,成语是First-Second
.
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
.
因此,您可以将对 bagof/3
的调用简化为:
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.
然后你可以这样查询:
?- 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.
这篇关于基于多个事实的聚合解决方案的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!