PROLOG,是否可以将谓词的所有结果收集到列表中,而不使用内置谓词,例如 bagof 或 findall
PROLOG, Is it possible to collect all result from a predicate to a list, without using built in predicates, such as bagof or findall
例如,如果我有一个 Prolog 谓词,例如
a(A, B).
是否可以收集,给定 A 的值,是否可以将谓词 a 之后的所有 B 值收集到列表中,而不使用内置谓词,例如 bagof/3
或 findall/3
.
你有两个明显的选择(对我来说很明显;似乎还有更多)。一种是确实使用数据库来保存状态。这至少有一个陷阱:根据您决定为临时状态使用的名称,您可能会破坏程序保留的其他一些状态。这是所有语言都遇到的老“全局状态”/“全局变量”问题。
另一种选择是使用“局部变量”和对其进行非回溯赋值以保持临时状态。这很可能取决于实现。对于初学者,您可以查看 nb_setarg/3
for SWI-Prolog。
但是,鉴于您有 findall、bagof、setof,这两种解决方案都很愚蠢。你必须激发对其他东西的需求来取代它们。仅仅说“这可能吗”是不够的,因为它是可能的,但完全没有必要,除非你知道你没有告诉我们的其他事情。
这是一个使用其他内置函数的愚蠢 setof
的草图,虽然不是 assert
,也不完全是 @false 在评论中列出的那些。
我们将使用列表累加器来收集解决方案:
stupid_setof(Template, Goal, Set) :-
stupid_setof(Template, Goal, [], Set).
有两种情况需要考虑:要么 Goal
可以枚举我们目前还没有见过的解决方案,要么它可以枚举的唯一解决方案已经在我们的累加器中。
首先,没有我们没有见过的解决方案的情况。在这种情况下我们完成了。
stupid_setof(Template, Goal, SolutionsSeen, Set) :-
\+ ( call(Goal),
\+ member(Template, SolutionsSeen) ),
!,
sort(SolutionsSeen, Set).
现在是愚蠢的部分。考虑:
foo(a).
foo(b).
foo(c).
?- SolutionsSeen = [], foo(X), \+ member(X, SolutionsSeen), !.
SolutionsSeen = [],
X = a.
?- SolutionsSeen = [a], foo(X), \+ member(X, SolutionsSeen), !.
SolutionsSeen = [a],
X = b.
?- SolutionsSeen = [a, b], foo(X), \+ member(X, SolutionsSeen), !.
SolutionsSeen = [a, b],
X = c.
?- SolutionsSeen = [a, b, c], foo(X), \+ member(X, SolutionsSeen), !.
false.
所以给定我们以前见过的解决方案列表,我们可以强制 Goal
回溯,直到它给我们一个我们以前没有见过的解决方案。请注意,这些查询是独立的:在每个查询中,我们都有一个从 a
.
开始枚举的 foo(X)
目标的全新副本
我们可以通过在调用它之前复制原始目标,以编程方式做同样的事情,迫使它从 Goal
的新实例开始新的枚举。如果这找到了一个新的解决方案,我们可以将它添加到我们的解决方案中,然后重复目标的另一个新副本,迫使它枚举另一个新的解决方案,依此类推:
stupid_setof(Template, Goal, SolutionsSeen, Set) :-
copy_term(Goal-Template, GoalInstance-Solution),
call(GoalInstance),
\+ member(Solution, SolutionsSeen),
!,
stupid_setof(Template, Goal, [Solution | SolutionsSeen], Set).
如果Goal
有N
个答案,这将按N**2
个的顺序枚举,并在解决方案列表中进行相应的线性搜索。它还将执行 Goal
多次出现的任何副作用。
但它“有效”:
?- stupid_setof(X, foo(X), Xs).
Xs = [a, b, c].
而且,尽管它很愚蠢,但如果 Goal
没有解决方案,这仍然比标准 setof/3
更愚蠢:
:- dynamic bar/1. % no clauses
?- setof(X, bar(X), Set).
false.
?- stupid_setof(X, bar(X), Set).
Set = [].
例如,如果我有一个 Prolog 谓词,例如 a(A, B).
是否可以收集,给定 A 的值,是否可以将谓词 a 之后的所有 B 值收集到列表中,而不使用内置谓词,例如 bagof/3
或 findall/3
.
你有两个明显的选择(对我来说很明显;似乎还有更多)。一种是确实使用数据库来保存状态。这至少有一个陷阱:根据您决定为临时状态使用的名称,您可能会破坏程序保留的其他一些状态。这是所有语言都遇到的老“全局状态”/“全局变量”问题。
另一种选择是使用“局部变量”和对其进行非回溯赋值以保持临时状态。这很可能取决于实现。对于初学者,您可以查看 nb_setarg/3
for SWI-Prolog。
但是,鉴于您有 findall、bagof、setof,这两种解决方案都很愚蠢。你必须激发对其他东西的需求来取代它们。仅仅说“这可能吗”是不够的,因为它是可能的,但完全没有必要,除非你知道你没有告诉我们的其他事情。
这是一个使用其他内置函数的愚蠢 setof
的草图,虽然不是 assert
,也不完全是 @false 在评论中列出的那些。
我们将使用列表累加器来收集解决方案:
stupid_setof(Template, Goal, Set) :-
stupid_setof(Template, Goal, [], Set).
有两种情况需要考虑:要么 Goal
可以枚举我们目前还没有见过的解决方案,要么它可以枚举的唯一解决方案已经在我们的累加器中。
首先,没有我们没有见过的解决方案的情况。在这种情况下我们完成了。
stupid_setof(Template, Goal, SolutionsSeen, Set) :-
\+ ( call(Goal),
\+ member(Template, SolutionsSeen) ),
!,
sort(SolutionsSeen, Set).
现在是愚蠢的部分。考虑:
foo(a).
foo(b).
foo(c).
?- SolutionsSeen = [], foo(X), \+ member(X, SolutionsSeen), !.
SolutionsSeen = [],
X = a.
?- SolutionsSeen = [a], foo(X), \+ member(X, SolutionsSeen), !.
SolutionsSeen = [a],
X = b.
?- SolutionsSeen = [a, b], foo(X), \+ member(X, SolutionsSeen), !.
SolutionsSeen = [a, b],
X = c.
?- SolutionsSeen = [a, b, c], foo(X), \+ member(X, SolutionsSeen), !.
false.
所以给定我们以前见过的解决方案列表,我们可以强制 Goal
回溯,直到它给我们一个我们以前没有见过的解决方案。请注意,这些查询是独立的:在每个查询中,我们都有一个从 a
.
foo(X)
目标的全新副本
我们可以通过在调用它之前复制原始目标,以编程方式做同样的事情,迫使它从 Goal
的新实例开始新的枚举。如果这找到了一个新的解决方案,我们可以将它添加到我们的解决方案中,然后重复目标的另一个新副本,迫使它枚举另一个新的解决方案,依此类推:
stupid_setof(Template, Goal, SolutionsSeen, Set) :-
copy_term(Goal-Template, GoalInstance-Solution),
call(GoalInstance),
\+ member(Solution, SolutionsSeen),
!,
stupid_setof(Template, Goal, [Solution | SolutionsSeen], Set).
如果Goal
有N
个答案,这将按N**2
个的顺序枚举,并在解决方案列表中进行相应的线性搜索。它还将执行 Goal
多次出现的任何副作用。
但它“有效”:
?- stupid_setof(X, foo(X), Xs).
Xs = [a, b, c].
而且,尽管它很愚蠢,但如果 Goal
没有解决方案,这仍然比标准 setof/3
更愚蠢:
:- dynamic bar/1. % no clauses
?- setof(X, bar(X), Set).
false.
?- stupid_setof(X, bar(X), Set).
Set = [].