pos*_*ist 14 prolog backtracking
我一直试图理解如何从回溯的Prolog谓词中产生一系列值.内置谓词between/3将在回溯时一次生成一个范围内的所有整数,因此编写它的示例可以帮助我完成任务.
我在现有的Prolog系统中寻找了一个实现,但between/3GNU Prolog 的实现是一个C函数,其技巧是调用另一个C函数"Pl_Create_Choice_Point",它允许它在回溯时产生额外的值.
sea*_*mcl 12
bet(N, M, K) :- N =< M, K = N.
bet(N, M, K) :- N < M, N1 is N+1, bet(N1, M, K).
Run Code Online (Sandbox Code Playgroud)
在行动:
$ swipl
?- [bet].
% bet compiled 0.00 sec, 1,064 bytes
true.
?- bet(1,5, K).
K = 1 n
K = 2 n
K = 3 n
K = 4 n
K = 5 n
false.
Run Code Online (Sandbox Code Playgroud)
如果使用剪切,则可以防止最终搜索失败,并恢复/ 3行为之间的确切内置:
bet(N, M, K) :- N < M, K = N.
bet(N, M, K) :- N == M, !, K = N.
bet(N, M, K) :- N < M, N1 is N+1, bet(N1, M, K).
Run Code Online (Sandbox Code Playgroud)
在行动:
?- [bet].
% bet compiled 0.00 sec, 416 bytes
true.
?- between(1,5,K).
K = 1 n
K = 2 n
K = 3 n
K = 4 n
K = 5.
?- [bet].
% bet compiled 0.00 sec, 240 bytes
true.
?- bet(1,5,K).
K = 1 n
K = 2 n
K = 3 n
K = 4 n
K = 5.
Run Code Online (Sandbox Code Playgroud)
你真正要问的是如何创建一个选择点.只要您成功统一,就可以获得解决方案.这就是@seanmcl的第一个谓词中发生的事情:
bet(N, M, K) :- N =< M, K = N.
Run Code Online (Sandbox Code Playgroud)
要获得选择点,您需要有其他选择.在Prolog中只有两种方法可以获得替代方法:使用明确的"或":;或者提供另一种规则.@seanmcl的代码给出了另一条规则,这是这种情况的惯用语.
再举一个例子,member/2为列表中的每个项生成一个解决方案,但是没有神奇的C函数需要,只有两个规则:
member(X, [X|_]).
member(X, [_|Xs]) :- member(X, Xs).
Run Code Online (Sandbox Code Playgroud)
让我们来看看这里发生了什么member(X, [1,2]).首先,使用第一条规则并[X|_]与之统一[1,2],生成X=1,_=[2].这是一个成功的统一,因此生成了一个解决方案.如果失败(例如按下;控制台),则启动回溯.下一个选择点在两个规则之间,因此输入下一个规则.[_|Xs]与[1,2]统一,产生绑定Xs=[2]然后member(X, [2])被调用.重新进入后,可以再次做出相同的决定,因此member(X, [X|_])应用第一个规则并生成X=2绑定.这是一个解决方案.如果你再次回溯,你会得到一个无害的失败,因为这两个规则都没有统一[].
我希望这有助于了解情况.