稍后更新:以下内容不太正确,最好转到父参考:Prolog 运算符 ^ 是什么?
所以,只关注setof/3
setof((P1,C),P^R^Bag,PS)
让我们Bag
用它的语法等价替换前面的一行:
setof((P1,C),P^R^search(P,P1,R,C),PS)
的描述setof/3
说它
- 将参数 2 称为目标;
- 根据参数 1,模板收集解决方案;
- 将模板的结果放入参数 3,即bag中,省略重复项。
所以在这种情况下,setof/3
会调用 (把表达式交给 Prolog 处理器来证明) search(P,P1,R,C)
,当这个成功时,收集结果值P1
,C
作为一个连词 (P1,C)
(这真的很特别,为什么不使用一个 2 元素列表?)并放入一切进入PS
让我们尝试一个类似于上面的可运行示例,使用列表而不是连词并使用不同的名称:
search(1,a,n,g).
search(2,a,m,g).
search(2,a,m,j).
search(1,a,m,j).
search(3,a,w,j).
search(3,a,v,j).
search(2,b,v,g).
search(3,b,m,g).
search(5,b,m,g).
search(1,b,m,j).
search(1,b,v,j).
search(2,b,w,h).
get_closed(Bag) :- setof([X,Y],P^R^search(P,X,R,Y),Bag).
get_open(Bag,P,R) :- setof([X,Y], search(P,X,R,Y),Bag).
注意你可以写
get_closed(Bag) :- setof([X,Y],P^R^search(P,X,R,Y),Bag).
没有关于“单例变量”的编译器警告,而
get_open(Bag) :- setof([X,Y],search(P,X,R,Y),Bag).
会给你投诉:
Singleton variables: [P,R]
这是有原因的:P
并且R
在“子句级别”可见。在这里,我们将P
和添加R
到头部,以便稍后为我们提供良好的打印输出。
封闭式解决方案
我们可以做的:
?- get_closed(Bag).
Bag = [[a, g], [a, j], [b, g], [b, h], [b, j]].
Bag
现在包含所有可能的解决方案[X,Y]
:
search(P,X,P,Y)
我们不关心内部目标之外的( P
, R
)元组的值。P
和的值R
在 调用的目标之外是不可见的setof/3
,回溯保持“内部”。
[X,Y]
由于不同( P
, R
)的替代解决方案 被 折叠setof/3
。如果有人bagof/3
改用:
?- bagof([X,Y],P^R^search(P,X,R,Y),Bag).
Bag = [[a, g], [a, g], [a, j], [a, j], [a, j], [a, j], [b, g], ....
实际上,对 Prolog 处理器的查询是:
Construct Bag
,它是[X,Y]
这样的列表:
∀ [X,Y]
: ∃<code>P,∃<code>R:search(P,X,R,Y)
为真。
开放式解决方案
?- get_open(Bag,P,R).
Bag = [[a, j], [b, j]],
P = 1,
R = m ;
Bag = [[a, g]],
P = 1,
R = n ;
Bag = [[b, j]],
P = 1,
R = v ;
Bag = [[a, g], [a, j]],
P = 2,
R = m ;
Bag = [[b, g]],
P = 2,
R = v ;
Bag = [[b, h]],
P = 2,
R = w ;
Bag = [[b, g]],
P = 3,
R = m ;
Bag = [[a, j]],
P = 3,
R = v ;
Bag = [[a, j]],
P = 3,
R = w ;
Bag = [[b, g]],
P = 5,
R = m.
在这种情况下,Bag
包含固定 ( P
, R
)元组的所有解决方案,Prolog 允许您在谓词级别回溯可能的( P
, R
) 。setof/3
变量P
和R
在setof/3
.
实际上,对 Prolog 处理器的查询是:
构造P
,R
这样:
您可以构造Bag
,它是[X,Y]
这样的列表
∀ [X,Y]
:search(P,X,R,Y)
是真的。
记号问题
如果 Prolog 有一个 Lambda 运算符来指示跨级别附加点(即元谓词和谓词之间)的位置,这将更清楚。假设 insetof/3
保持不变setof/3
(Prolog 的相反态度),可以这样写:
get_closed(Bag) :- setof([X,Y],λX.λY.search(P,X,R,Y),Bag).
或者
get_closed(Bag) :- setof([X,Y],search(P,X,R,Y),Bag).
和
get_open(Bag) :- λP.λR.setof([X,Y],search(P,X,R,Y),Bag).
或者可以简单地写
get_closed(Bag) :- setof([X,Y],search_closed(X,Y),Bag).
search_closed(X,Y) :- search(_,X,_,Y).
这也将清楚发生了什么,因为变量没有在它们出现的子句之外导出。