正如我似乎再也找不到的另一个StackOverflow答案中指出的那样,这种模式在实用的Prolog代码中经常出现:
pred(X) :-
guard(X),
...
pred(X) :-
\+ guard(X),
...
许多人试图将其浓缩为
pred(X) :-
(guard(X) ->
...
;
...).
但是,众所周知,箭头结构破坏了选择点,而且不合逻辑。
在Ulrich Neumerkel和Stefan Kral的"this construct is rarely used,"中,提出了一个名为if_/3
的谓词,该谓词是单调且合乎逻辑的,但是在论文中,他们提到了另一个引起我注意的结构:*->
。
*->
构造函数的功能完全类似于上面的未使用过的guard子句示例,因此,由于我不想拥有if_/3
和我所要求的条件化条件,因此它似乎非常适合我的使用不太在乎额外的选择点。如果我没记错的话(编辑:我是),它提供与if_/3
相同的语义,但不需要在条件谓词上添加“验证”。
但是在SWI文档中,它声称{{3}}对我来说似乎很奇怪。在您尝试进行纯逻辑编程时,*->
在我看来似乎比->
更好。有什么理由要避免这种结构,还是有一个更好的替代方案来代替整个保护子句/否定的保护子句模式?
答案 0 :(得分:4)
让我们尝试一下!您提供的模式是:
pred(X) :- ( guard(X) -> ... ; ... ).
我现在使用(*->)/2
并按如下所示填写“ ...”:
pred(X) :- ( guard(X) *-> false ; true ).
进一步,我以guard/1
的形式定义了明显的 pure 谓词:
guard(a).
现在,让我们问pred/1
最普遍的查询:有没有解决办法?
?- pred(X). false.
因此,根据谓词,没有X
这样的名词pred(X)
。
但这是错误,因为实际上有这样的术语:
?- pred(b). true.
实际上,pred/1
有无限多个解决方案。在这种情况下,谓词状态根本不存在是可以接受的吗?当然,因为答案是极其有效地计算的,不是吗?
我们得出结论,(*->)/2
具有(->)/2
的一个重要缺点:如果不同,它可能会错误地提交给其中一个分支。如果仅进一步实例化条件中出现的变量,则分支将适用。以此方式依赖其参数的 instantiation 的谓词永远不可能是纯净的,因为它抵消了我们期望适用于纯逻辑程序的单调推理。特别是,从逻辑上讲,由于pred(b)
成立,我们希望pred(X)
(对pred(b)
的概括)必须不能失败< / em>。一旦此属性中断,您将无法再使用声明性调试和其他重要方法来让您更轻松地理解,推理和管理Prolog程序,而这首先构成了声明式编程的主要吸引力。
您提到的问题可能是What uses does if_3/
have?。
答案 1 :(得分:1)
通常命名为 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的*->/2
变体和https://github.com/LogtalkDotOrg/logtalk3/tree/master/tests/prolog/control/if_3的if/3
变体提供了针对此控制结构的单元测试。