Prolog if-then-else 构造:-> vs *-> vs. if_/3

Prolog if-then-else constructs: -> vs *-> vs. if_/3

正如我似乎再也找不到的另一个 Whosebug 答案中指出的那样,这种模式经常出现在实际的 Prolog 代码中:

pred(X) :-
    guard(X),
    ...
pred(X) :-
    \+ guard(X),
    ...

许多人试图将其浓缩为

pred(X) :-
    (guard(X) ->
    ...
    ;
    ...).

然而众所周知,箭头结构破坏了选择点,不符合逻辑。

在 Ulrich Neumerkel 和 Stefan Kral 的 Indexing dif/2 中,提出了一个叫做 if_/3 的谓词,它是单调的和合乎逻辑的,但是在论文中他们提到了另一个引起我注意的结构:*->.

*-> 构造函数与上面的无糖保护子句示例完全相同,因此它似乎非常适合我的使用,因为我不想有 if_/3 要求的具体化条件而且我不太关心额外的选择点。如果我没有弄错(编辑:我是),它提供与 if_/3 相同的语义,但不需要将 "reification" 添加到条件谓词。

但是在它的 SWI 文档中,它声称 "this construct is rarely used," 这对我来说似乎很奇怪。 *-> 在我看来,当您尝试进行纯逻辑编程时,它绝对比 -> 好。是否有任何理由避免这种结构,或者是否有更好的替代整个保护子句/否定保护子句模式?

通常命名为 soft-cut 的控制结构在多个 Prolog 系统中可用。 CxProlog、ECLiPSe、JIProlog、SWI-Prolog 和 YAP 将其作为 *->/2 谓词和中缀运算符提供。 Ciao Prolog、SICStus Prolog 和 YAP 提供了具有相同语义的 if/3 谓词。

我对这个soft-cut控制构造的主要用途是在Logtalk的coinduction实现中,它起到了关键作用.除了这种情况,我很少使用它。

->/2,另一方面,它被广泛使用。 if 部分中的隐式切割对于构造而言是局部的,并且它的使用避免了,如您的示例中那样,试图两次证明守卫,这在计算上可能很昂贵。它可能不是纯粹的,但是,与剪辑一样,只要您完全了解它的优缺点,它就是一个有用的控制结构。

P.S。 Logtalk 为 https://github.com/LogtalkDotOrg/logtalk3/tree/master/tests/prolog/control/soft_cut_2_3 and for the if/3 variant at https://github.com/LogtalkDotOrg/logtalk3/tree/master/tests/prolog/control/if_3

处的 *->/2 变体提供了此控制结构的单元测试

我们来试试吧!你给的模式是:

pred(X) :-
    (    guard(X) ->
         ...
    ;    ...
    ).

我现在用的是(*->)/2,“...”填写如下:

pred(X) :-
        (   guard(X) *->
            false
        ;   true
        ).

此外,作为guard/1,我定义了明显的谓词:

guard(a).

现在,让我们问pred/1 最一般的查询有没有解决方案?

?- pred(X).
false.

因此,根据谓词,没有项 X 使得 pred(X) 为真

但那是错误的,因为实际上有这样一个词:

?- pred(b).
true.

事实上,pred/1无限多个解。在这种情况下,谓词声明 none 是否可以接受?当然可以,因为答案的计算非常高效,不是吗?

我们得出结论,(*->)/2(->)/2 有一个重要的缺点:它可能 不正确地 提交到其中一个分支 different 如果仅进一步实例化条件中出现的变量,则分支将适用。以这种方式依赖于其参数的 实例化 的谓词永远不可能是纯粹的,因为它抵消了我们期望适用于纯逻辑程序的单调推理。特别地,从逻辑的角度来看,由于pred(b)成立,我们期望pred(X),这是pred(b)、[=46=的泛化 ]一定不能失败。一旦这个 属性 中断,您将无法再应用声明式调试和其他重要方法,这些方法可以让您更轻松地理解、推理和管理 Prolog 程序,而这些首先构成了声明式编程的主要吸引力。

你提的问题大概是.