灵感来自
我想尝试一下“Prolog中的RDBMS操作”(实际上,这或多或少是Datalog)
问题陈述
给定一个“主演电影演员”的数据库:
starsin(a,bob).
starsin(c,bob).
starsin(a,maria).
starsin(b,maria).
starsin(c,maria).
starsin(a,george).
starsin(b,george).
starsin(c,george).
starsin(d,george).
并给定一组电影,找到在该组所有电影中出演的演员。
我首先有一个丑陋的解决方案,但后来......
很好的解决方案
澄清问题:
集合由没有重复的列表表示,可能是有序的。
- 给定一组电影
MovIn
- ... 找到演员集
ActOut
- ... ...这样:每个演员都
ActOut
出现在(至少)所有电影中MovIn
- ... ... 重新制定:任何演员的电影 集都是.
MovAx
Ax
ActOut
MovIn
setof/3似乎是正确的顶级谓词。第 1 点和第 2 点的Ansatz是:
setof(Ax, (... MovIn ...) , ActOut).
如果MovAx
是出现的电影集,Ax
我们可以使用
- 库的 子集/2 (列表)或
- ord_subset/2 of library(ordset) ...如果我们可以确保 evertyhing 是一个 ordset。
让我们使用subset/2
.
第 4 点似乎让我们写道:
setof(Ax, (..., subset(MovAx, MovIn)) , ActOut).
开发...
...
setof(Ax, ( setof(Mx,starsin(Mx,Ax),MovAx) , subset(MovIn, MovAx) ) , ActOut).
这似乎已经是它了!
有 λ 表达式但在键盘或语法中没有 λ 时的感觉。
完毕!
总结为谓词:
actors_appearing_in_movies(MovIn,ActOut) :-
setof(Ax, ( setof(Mx,starsin(Mx,Ax),MovAx) , subset(MovIn, MovAx) ) , ActOut).
不幸的是,上述方法不起作用。
正在进行回溯,显然我需要将所有内容包装到另一个setof/3
中,但是为什么呢?
?- actors_appearing_in_movies([a,b],ActOut).
ActOut = [maria] ;
ActOut = [george].
完成了,拿两个
以下确实有效:
subselect(Ax,MovIn) :-
setof(Mx,starsin(Mx,Ax),MovAx), subset(MovIn, MovAx).
actors_appearing_in_movies(MovIn,ActOut) :-
setof(Ax, subselect(Ax,MovIn) , ActOut).
?- actors_appearing_in_movies([a,b],ActOut).
ActOut = [george, maria].
测试
测试只是运行几个目标。
请注意,对于空电影集,我们获取所有演员。这可以说是正确的:每个演员都出演了空场的所有电影。
actors_appearing_in_movies([],ActOut),permutation([bob, george, maria],ActOut),!.
actors_appearing_in_movies([a],ActOut),permutation([bob, george, maria],ActOut),!.
actors_appearing_in_movies([a,b],ActOut),permutation([george, maria],ActOut),!.
actors_appearing_in_movies([a,b,c],ActOut),permutation([george, maria],ActOut),!.
actors_appearing_in_movies([a,b,c,d],ActOut),permutation([george],ActOut),!.
问题
我错过了什么
actors_appearing_in_movies(MovIn,ActOut) :-
setof(Ax, ( setof(Mx,starsin(Mx,Ax),MovAx) , subset(MovIn, MovAx) ) , ActOut).