Prolog 多个事实的聚合解
正在尝试创建一个谓词(Prolog 多个事实的聚合解,prolog,duplicates,aggregate,Prolog,Duplicates,Aggregate,正在尝试创建一个谓词(timePeriod/2),用于计算特定事实的两个日期之间的时间段。我自己设法做到了这一点,但当“其他答案”出现在同一个列表中时,我会面临一些问题(例如,更容易用例子解释) 我有以下知识基础事实 popStar('Jackson',1987,1991). popStar('Jackson',1992,1996). popStar('Michaels',1996,2000). popStar('Newcastle',2000,2007). popStar('Bowi
timePeriod/2
),用于计算特定事实的两个日期之间的时间段。我自己设法做到了这一点,但当“其他答案”出现在同一个列表中时,我会面临一些问题(例如,更容易用例子解释)
我有以下知识基础事实
popStar('Jackson',1987,1991).
popStar('Jackson',1992,1996).
popStar('Michaels',1996,2000).
popStar('Newcastle',2000,2007).
popStar('Bowie',2008,2010).
下面的函数计算特定事实的日期间隔时间(如下所示)
谓词(时间段/2)
timePeriod(PS,X) :-
bagof((Name,Start,End),popStar(Name,Start,End),PSs),X is End-Start+1)
以鲍伊为例;它返回X=3
(这是正确的)
但是,当列表中有重复项且有多个答案可用时,谓词只声明“false”。以事实“Jackson”为例,我希望能够计算两个事实的两个时间段;同时,
因此,如果谓词对这两个Jackson事实都有效,那么谓词timePeriod
将声明X=10
如果有人能建议如何更改以使其正常工作,我将不胜感激
谢谢 您可能不太了解
foreach/3
的功能。我想我也不完全理解每个人的想法。我确信它与我们说的不一样:
for each x in xs:
do foo(x)
另一件事:Prolog中的“元组”不是您所期望的,它来自Python或Haskell之类的语言。这个:(a,b,c)
实际上是:,(a),(b,c))
。更好的方法是使用一个简单的术语,一般形式是三重(a,b,c)
。对于一对,习惯用法是First Second
因此,您可以将对bagof/3
的调用简化为:
?- 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].
一旦你有了如上所述的列表,你就需要对差异进行汇总,这可能类似于:
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.
您可能不太了解
foreach/3
的功能。我想我也不完全理解每个人的想法。我确信它与我们说的不一样:
for each x in xs:
do foo(x)
另一件事:Prolog中的“元组”不是您所期望的,它来自Python或Haskell之类的语言。这个:(a,b,c)
实际上是:,(a),(b,c))
。更好的方法是使用一个简单的术语,一般形式是三重(a,b,c)
。对于一对,习惯用法是First Second
因此,您可以将对bagof/3
的调用简化为:
?- 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].
一旦你有了如上所述的列表,你就需要对差异进行汇总,这可能类似于:
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.
SWI Prolog有一个易于处理的聚合:它基于标准的“所有解决方案”谓词,如findall/3、setof/3、bagof/3,因此您应该首先掌握这些谓词的基本知识(正如Boris在回答中所解释的)。使用该库,只需一个查询即可解决您的问题:
timePeriod(PS,X) :-
aggregate(sum(P), B^E^(popStar(PS,B,E),P is E-B+1), X).
SWI Prolog有一个易于处理的聚合:它基于标准的“所有解决方案”谓词,如findall/3、setof/3、bagof/3,因此您应该首先掌握这些谓词的基本知识(正如Boris在回答中所解释的)。使用该库,只需一个查询即可解决您的问题:
timePeriod(PS,X) :-
aggregate(sum(P), B^E^(popStar(PS,B,E),P is E-B+1), X).
事实上,
foreach/3
就在这个库中。事实上,foreach/3
就在这个库中。如果您使用的是一个特定于swi prolog的库(library(aggregate)
),那么您至少应该在那里留下prolog标记,甚至swi prolog如果您正在使用一个特定于swi prolog的库(library(aggregate)
),那么至少应该保留prolog标记,甚至swi prolog