【问题标题】:Prolog if-then-else constructs: -> vs *-> vs. if_/3Prolog if-then-else 结构:-> vs *-> vs. if_/3
【发布时间】:2018-10-31 16:30:06
【问题描述】:

正如我似乎再也找不到的另一个 StackOverflow 答案中所述,这种模式经常出现在实际的 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 相同的语义,但不需要在条件谓词中添加“具体化”。

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

【问题讨论】:

  • 如果我没记错的话,它提供的语义与if_/3 相同。你误会了。请参考2 Prolog 的 if-then-else 的声明性限制,最后一段:即使是 SICStus 和 SWI 的“软剪辑”版本if/3(*->)/2,也可以展示与 Prolog 的不合理否定相同的问题。
  • 这是if/3 的定义(效率不高,因为它执行了两次守卫):if(G_0, Then_0, _) :- G_0, Then_0. if(G_0, _, Else_0) :- \+ G_0, Else_0. 你看到\+?里面充满了杂质!

标签: if-statement prolog control-structure logical-purity implication


【解决方案1】:

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

预测(X):- (守卫(X)-> ... ; ... )。

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

预测(X):- (守卫(X)*-> ; )。

进一步,作为guard/1,我定义了明显的pure谓词:

守卫(a)。

现在,让我们问pred/1最通用的查询有什么解决办法吗?

?- pred(X)。 错误。

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

但那错了,因为其实有这样一个名词:

?- pred(b)。 是的。

事实上,pred/1无限多的解决方案。在这种情况下,谓词状态根本没有是可以接受的吗?当然,因为答案的计算非常有效,不是这样吗?

我们得出结论,(*->)/2(->)/2 有一个重要的缺点:它可能错误地 提交到其中一个分支,以防不同 分支适用如果只有条件中出现的变量被进一步实例化。以这种方式依赖于其参数的实例化的谓词永远不可能是纯的,因为它抵消了我们期望适用于纯逻辑程序的单调推理。特别是,从逻辑的角度来看,由于 pred(b) 成立,我们希望 pred(X)pred(b)概括不能失败。一旦这个属性被破坏,你就不能再应用声明式调试和其他重要的方法,这些方法让你更容易理解、推理和管理 Prolog 程序,而这些首先构成了声明式编程的主要吸引力。

你提到的问题大概是What uses does if_3/ have?

【讨论】:

  • 好的,我现在明白了。在我看来,如果我们让\+/1 以与dif/2 相同的方式工作(也就是说,它施加了一个永远不会证明某个表达式的约束),我们可以通过使*-> 得到正确的行为这样,如果测试子句失败(例如guard(X)),它会引入约束\+guard(X),我们可以避免if_/3子句的整个具体化,不是吗?
  • 请注意,让(\+)/1dif/2 工作方式相同,等于建设性否定。您可以在 7 General reification 中找到对此的讨论。至少从给出的示例来看,与if_/3 的“整体迂回”相比,一般具体化的成本要高得多。
  • @false 太棒了,感谢您的提示。似乎我们可以通过将原始示例更改为具有freeze(X, \+guard(X)) 来完成纯粹的行为,这看起来与if_/3 表单的工作方式相同。不过,我不确定这对性能的影响。
  • @NameMcChange:根据guard/1 的精确含义,您可能需要when(ground(X), \+ guard(X)) 或介于两者之间的东西。这正是建设性否定如此昂贵的原因。您或多或少需要一个元解释器来监视guard/1 的行为。
【解决方案2】:

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

我对这个 soft-cut 控件结构的主要用途是在 Logtalk 中实现 coinduction,它在其中起着关键作用。在这种情况下,我很少使用它。

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

附: Logtalk 为*->/2 变体https://github.com/LogtalkDotOrg/logtalk3/tree/master/tests/prolog/control/soft_cut_2_3if/3 变体https://github.com/LogtalkDotOrg/logtalk3/tree/master/tests/prolog/control/if_3 提供此控制结构的单元测试

【讨论】:

    猜你喜欢
    • 2012-03-09
    • 1970-01-01
    • 1970-01-01
    • 2017-06-08
    • 2019-10-22
    • 1970-01-01
    • 1970-01-01
    • 2012-03-05
    • 1970-01-01
    相关资源
    最近更新 更多