这个谓词为什么要这样写?

问题描述 投票:0回答:1

我很难理解为什么 findall 的第二个谓词要写成这样,而不是直接写成 collect_found([],L)

:- dynamic found/1.
findall(X, G, _) :-
   asserta(found(mark)),
   call(G),
   asserta(found(result(X))),
   fail.
findall(_, _, L) :- collect_found([], M), !, L = M.

collect_found(S, L) :-
   getnext(X),
   !,
   collect_found([X|S], L).
collect_found(L, L).

getnext(Y) :- retract(found(X)), !, X = result(Y).

这样写有什么好处吗?

prolog prolog-findall
1个回答
0
投票

(此代码来自 Clocksin 和 Mellish 的《Programming in Prolog》第 5 版。由于它与内置的

findall/3
冲突,我将使用名称
cmfindall/3
来定义它们)

首先回答你的问题:其实书上的代码和你的建议没有什么区别。因此:

cmfindall(_, _, L) :- collect_found([], M), !, L = M.

cmfindall(_, _, L) :- collect_found([], L).

(在这种情况下)是相同的。为了明白这一点,我们来看看

collect_found/2
的定义。第二个参数在其中起什么作用?为了更好地强调它,我将删除与第二个参数无关的所有内容:

collect_found(_, L) :-
   ...,
   !,
   collect_found(_, L).
collect_found(L, L).

由此可知,第二个论点只有在与第一个论点统一时,才在最后产生影响。因此,没有必要在目标实现后推迟统一。

为什么代码要这样写?作者似乎希望确保始终执行删除

found/1
事实,并且(可能在之前的 1981 年之前的版本中)第二个参数对实例化很敏感。

另请注意作者的评论(第 168 页,第 2 段):

在另一个

findall
的第二个参数中使用的任何
findall
都会被正确处理。

现在他们显然没有考虑:

?- cmfindall(X,(X=1;catch(cmfindall(Y,(Y=2;throw(ex)),_),ex,false)),Xs).
   Xs = [2], unexpected.
   Xs = [1]. % expected, but not found

正确处理此类情况是一项相当脏的工作,因为系统之间仍然没有就使用哪些原语来干净地处理它们达成一致。

© www.soinside.com 2019 - 2024. All rights reserved.