Prolog:涉及匿名变量的子句中的冗余结果

Alb*_*bre 3 prolog prolog-anonymous-variable

考虑以下 Prolog 程序。

a(X) :- b(_), c(X).

b(1).
b(2).
b(3).

c(1).
Run Code Online (Sandbox Code Playgroud)

运行查询:

a(X).
Run Code Online (Sandbox Code Playgroud)

在 SWI-Prolog 中,我们得到三个结果,所有 X = 1。

鉴于我们不关心匿名变量,是什么阻止了 SWI-Prolog 返回单个结果?为什么不执行此优化?

谢谢

Wil*_*sem 5

对于 Prolog 来说,下划线只是一个匿名变量。所以a/1谓词等价于:

a(X) :-
    b(Y),
    c(X).
Run Code Online (Sandbox Code Playgroud)

现在回溯该b(Y)子句可能看起来没有用,因为一旦它满足,Y就无处使用,因此不应该对程序的其余部分产生影响。再者Y没有影响X所以b(Y)应该不会有半点影响X

然而,在真正的 Prolog 中,有一些事情可能会产生影响:

  1. b/1谓词可能会执行I / O。假设谓词实现为:

    b(a) :-
        print(a).
    b(a) :-
        print(b).
    
    Run Code Online (Sandbox Code Playgroud)

    然后它将a在第一个分支和b第二个分支中打印。

  2. b/1可能会在第二个、第三个……路径中引发异常。在这种情况下,我们可能想要处理错误;

  3. b/1可能会使用asserta/1,assertz/1等并改变程序c/1例如,它可能会添加事实,以便在第二次运行时c/1有其他结果。

  4. 许多 Prolog 解释器都有一个不可回溯的存储,这样不同的回溯路径可以相互共享信息。

  5. 其他编码设施,这样的结果b/1可能会对c/1.

您可避免这种回溯过度b/1使用once/1元谓词。例如:

a(X) :-
    once(b(_)),
    c(X).
Run Code Online (Sandbox Code Playgroud)