Prolog中的谓词控制

Prolog中的谓词控制,prolog,predicate,Prolog,Predicate,对Prolog谓词控件有好奇心 假设我有一个谓词f(a,X)和g(B) 如果c返回false,我如何在谓词f(A,X)中继续计算g(X)。考虑例如 ?- false, writeln('Hello World!'). false. ?- ignore(false), writeln('Hello World!'). Hello World! true. 但是,如果c失败,为什么要继续?用例是什么 我在SWI Prolog中测试了这段代码,我不确定其他Prolog是否有false/0和igno

对Prolog谓词控件有好奇心

假设我有一个谓词f(a,X)和g(B)


如果c返回false,我如何在谓词
f(A,X)
中继续计算
g(X)
。考虑例如

?- false, writeln('Hello World!').
false.

?- ignore(false), writeln('Hello World!').
Hello World!
true.
但是,如果
c
失败,为什么要继续?用例是什么

我在SWI Prolog中测试了这段代码,我不确定其他Prolog是否有
false/0
ignore/1
。 后者可以这样定义:

ignore(Goal) :- Goal, !.
ignore(_).

如果您的意图是定义
f(A,X)
,以便评估
g(X)
是否
c
失败,则:

  • 您可以使用隐含(
    ->
    )和/或析取(
    )、对其进行编码
  • f(A,X)
    不需要用
    c
    来定义。这假设
    c
    没有任何副作用(例如,使用
    assert
    断言数据库事实,或将IO打印到流),这些副作用会改变环境,并且在
    c
    失败时无法撤消,在这种情况下,首选第一个选项 使用析取有几种选择,例如:

    f(A,X) :- ((a, b, c) ; (a, b)), g(X).
    
    此定义(如上)根本不依赖于
    c
    ,但它将始终执行
    c
    (只要
    a
    b
    成功)。析取(
    )允许PROLOG在
    c
    完全失败的情况下回溯尝试再次执行
    a、b
    ,并继续执行
    g(X)
    。请注意,这相当于:

    f(A,X) :- a, b, c, g(X).
    f(A,X) :- a, b, g(X).
    
    为了使PROLOG不会因为第二个(相同的)头谓词
    f(A,X)
    而回溯计算
    f(A,X)
    两次,您可以选择在第一个子句中的
    c
    子目标之后立即放置一个cut(
    ),如果您的实现支持的话。切割放在
    c
    之后,因为如果
    c
    失败,我们不希望解释器承诺选择
    f(A,X)
    子句,相反,我们希望解释器退出该子句并尝试下一个子句,有效地忽略
    c
    并继续处理
    g(X)

    还要注意,此解决方案依赖于
    a
    b
    没有副作用,因为当
    c
    失败时,
    a
    b
    会再次执行。如果所有
    a
    b
    c
    都有副作用,您可以尝试使用暗示:


    无论
    c
    是否失败,这也将始终有效地执行
    g(X)
    ,并且如果
    c
    失败,将不会再次执行
    a
    b
    。这种单一条款的定义也不会像前面的建议那样留下选择点

    +1询问为什么这会有用。可移植的失败谓词是
    fail
    ,顺便说一句。(实现起来很简单:
    fail:-0=1.
    )如果
    c
    失败,您可能希望继续的一种情况是
    c
    有副作用;有关更多详细信息,请参见我对这个问题的回答。
    f(A,X) :- a, b, c, g(X).
    f(A,X) :- a, b, g(X).
    
    f(A,X) :- a, b, (c -> g(X) ; g(X)).