在堆栈溢出的Prolog部分中,谓词 if_/3 似乎是fairly popular

该谓词是由@false提供的:

if_(If_1, Then_0, Else_0) :-
   call(If_1, T),
   (  T == true -> call(Then_0)
   ;  T == false -> call(Else_0)
   ;  nonvar(T) -> throw(error(type_error(boolean,T),_))
   ;  /* var(T) */ throw(error(instantiation_error,_))
   ).

但是,我无法找到一个清晰,简单,简洁的解释来说明此谓词的功能以及与例如Prolog if -> then ; else的经典if-then-else构造。

我发现的大多数链接都直接使用此谓词,而对其使用原因的解释却很少,Prolog的非专家可以轻松理解。

最佳答案

在老式的Prolog代码中,以下模式经常出现:

谓词([],...)。
谓词([L | Ls],...):-
条件(L)
然后(Ls,...)。
谓词([L | Ls],...):-
\ +条件(L),
else(Ls,...)。

我在这里使用列表作为发生这种情况的示例(例如参见include/3exclude/3等),尽管这种模式当然也发生在其他地方。

悲剧如下:

  • 对于实例化的列表,模式匹配可以将第一个从句与其余两个从句区别开来,但无法将第二个从最后一个从句中区别开,因为它们都将'.'(_, _)作为主要函子和第一个参数的统一性。
  • 最后两个子句适用的条件显然是互斥
  • 因此,当一切都已知时,我们希望获得一个高效的确定性谓词,该谓词不会留下选择点,理想情况下甚至不会创建选择点。
  • 但是,只要不能安全地确定所有内容,我们就希望从回溯中受益,以了解所有解决方案,因此我们无法承担任何一个条款。

  • 总而言之,现有的构造和语言功能都无法以某种方式表达实践中经常出现的模式。因此,几十年来,似乎有必要妥协。您可以对Prolog社区中的“妥协”通常朝哪个方向做出很好的猜测:几乎总是会在准确性方面牺牲正确性,以免产生疑问。毕竟,只要您的程序运行速度快,谁会关心正确的结果,对吗?因此,在发明if_/3之前,这经常被错误地写为:

    谓词([],...)。
    谓词([L | Ls],...):-
    (条件(L)->
    然后(Ls,...)。
    ; else(Ls,...)。
    )

    此处的错误当然是,当元素没有被充分实例化时,即使这两种选择在逻辑上都是可行的,这也可能会错误地提交给一个分支。因此,使用if-then-else几乎总是声明错误,并且由于违反了我们希望从纯Prolog程序获得的最基本属性,因此在声明性调试方法中占据了很大的比例。

    使用if_/3,您可以这样编写:

    谓词([],...)。
    谓词([L | Ls],...):-
    if_(condition(L),
    然后(Ls,...),
    else(Ls,...))。

    保留所有期望的方面。这是:
  • 确定性是否可以安全地确定一切
  • 高效,因为它甚至不创建选择点
  • 完成,因为您永远不会错误地提交到一个特定的分支。

  • 的价格相当实惠:正如鲍里斯在评论中提到的那样,您需要实现。我现在对此有一些经验,并且发现通过一些实践很容易。

    大家好消息:在许多情况下,condition的形式为(=)/2(#=)/2,并且第一个甚至附带 library(reif) 以获得免费的

    有关更多信息,请参阅Ulrich Neumerkel和Stefan Kral的Indexing dif/2!

    关于if-statement - if_/3有什么用?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39833370/

    10-13 22:31