我有以下事实和规则:
% frequents(D,P) % D=drinker, P=pub
% serves(P,B) % B=beer
% likes(D,B)
frequents(janus, godthaab).
frequents(janus, goldenekrone).
frequents(yanai, goldenekrone).
frequents(dimi, schlosskeller).
serves(godthaab, tuborg).
serves(godthaab, carlsberg).
serves(goldenekrone, pfungstaedter).
serves(schlosskeller, fix).
likes(janus, tuborg).
likes(janus, carlsberg).
count_good_beers_for_at(D,P,F) :- group_by((frequents(D,P), serves(P,B), likes(D,B)),[D,P],(F = count)).
possible_beers_served_for_at(D,P,B) :- lj(serves(P,B), frequents(D,R), P=R).
现在我想构建一个规则,当一个“饮酒者”“频繁”的每个酒吧的可用“喜欢”啤酒的数量大于0时,它应该像谓词返回“true”一样工作。
当规则没有返回元组时,我会认为谓词是真的。如果谓词是假的,我打算让它返回没有单一“喜欢”啤酒的酒吧。
正如你所看到的,我已经有一条规则可以在给定的酒吧里为特定饮酒者计算好啤酒。我也有一条规则给我可用的啤酒数量。
DES> count_good_beers_for_at(A,B,C)
{
count_good_beers_for_at(janus,godthaab,2)
}
Info: 1 tuple computed.
正如您所看到的,柜台不会返回经常光顾的酒吧,但却有0个喜欢的啤酒。我打算通过使用左外连接来解决这个问题。
DES> is_happy_at(D,P,Z) :- lj(serves(P,B), count_good_beers_for_at(D,Y,Z), (Y=P))
Info: Processing:
is_happy_at(D,P,Z) :-
lj(serves(P,B),count_good_beers_for_at(D,Y,Z),Y = P).
{
is_happy_at(janus,godthaab,2),
is_happy_at(null,goldenekrone,null),
is_happy_at(null,schlosskeller,null)
}
Info: 3 tuples computed.
这几乎是正确的,除了它还给了我没有经常光顾的酒吧。我尝试添加一个额外的条件:
DES> is_happy_at(D,P,Z) :- lj(serves(P,B), count_good_beers_for_at(D,Y,Z), (Y=P)), frequents(D,P)
Info: Processing:
is_happy_at(D,P,Z) :-
lj(serves(P,B),count_good_beers_for_at(D,Y,Z),Y = P),
frequents(D,P).
{
is_happy_at(janus,godthaab,2)
}
Info: 1 tuple computed.
现在我以某种方式过滤了包含空值的所有内容!我怀疑这是由于DES中的空值逻辑。
我认识到我可能会以错误的方式接近整个问题。任何帮助表示赞赏。
编辑:作业是“非常快乐(D)ist wahr,genau dann wenn jede Bar,die Trinker D besucht,wenigstens ein Bier ausschenkt,das er mag。”这意味着“ very_happy(D)是真的,如果每个酒吧饮酒者D访问,至少服用1啤酒,他喜欢”。由于这个任务是关于Datalog的,我认为绝对可以在不使用Prolog的情况下解决。
答案 0 :(得分:4)
我认为,对于您的分配,您应该使用基本的Datalog,而不会滥用聚合。问题的关键是如何表达普遍量化的条件。我搜索了“通用量化数据记录”,并在第一个位置找到了deductnotes.pdf断言:
普遍量化的条件只能用存在量化和否定的等价条件来表达。
在该PDF中,你会发现一个有用的例子(pagg 9& 10)。
因此,我们必须重新提出我们的问题。我最终得到了这段代码:
not_happy(D) :-
frequents(D, P),
likes(D, B),
not(serves(P, B)).
very_happy(D) :-
likes(D, _),
not(not_happy(D)).
这似乎是必要的:
DES> very_happy(D)
{
}
Info: 0 tuple computed.
注意likes(D, _)
,这是避免将yanai和dimi列为very_happy所必需的,没有明确断言他们喜欢什么(对不起我的英语真的很糟糕......)
编辑:对不起,但上述解决方案无效。我用这种方式重写了它:
likes_pub(D, P) :-
likes(D, B),
serves(P, B).
unhappy(D) :-
frequents(D, P),
not(likes_pub(D, P)).
very_happy(D) :-
likes(D, _),
not(unhappy(D)).
试验:
DES> unhappy(D)
{
unhappy(dimi),
unhappy(janus),
unhappy(yanai)
}
Info: 3 tuples computed.
DES> very_happy(D)
{
}
Info: 0 tuples computed.
现在我们添加一个事实:
serves(goldenekrone, tuborg).
我们可以看到更正的代码结果:
DES> unhappy(D)
{
unhappy(dimi),
unhappy(yanai)
}
Info: 2 tuples computed.
DES> very_happy(D)
{
very_happy(janus)
}
Info: 1 tuple computed.
答案 1 :(得分:2)
也许不是你期待的答案。但你可以使用普通的Prolog,并通过bagof / 3或setof / 3内置谓词轻松地进行分组。
?- bagof(B,(frequents(D,P), serves(P,B), likes(D,B)),L), length(L,N).
D = janus,
P = godthaab,
L = [tuborg,carlsberg],
N = 2
bagof / 3的语义是这样的,它不计算给定查询的外连接。查询通常由Prolog执行。结果首先累积并按键排序。最后,通过回溯返回结果。如果你的数据记录不能没有空值,那么你必须过滤。
但是当你只想知道喜欢啤酒的存在时,你不需要进入聚合。您可以通过查询直接执行此操作而无需任何聚合:
is_happy_at(D,P) :- frequents(D,P), once((serves(P,B), likes(D,B))).
?- is_happy_at(D,P).
D = janus,
P = godthaab ;
Nein
一次/ 1可防止不必要的回溯。当数据记录在is_happy_at / 2中看到投影时,它可能会自动不进行不必要的回溯,即B被投射掉。或者您可能需要显式使用与SQL DISTINCT对应的内容。或者最终你的数据记录为你提供了与SQL EXISTS相对应的东西,它最接近于一次/ 1。
再见