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 程序,而这些首先构成了声明式编程的主要吸引力。
你提的问题大概是.
正如我似乎再也找不到的另一个 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 程序,而这些首先构成了声明式编程的主要吸引力。
你提的问题大概是