【问题标题】:Ensuring that a predicate succeeds deterministically确保谓词确定性地成功
【发布时间】:2016-02-01 21:08:17
【问题描述】:

This other question 问的几乎一样,但不完全一样。相反,我如何要求一个目标确定地成功(恰好一次)并且不留下任何选择点?

这在用作命令行工具的 Prolog 程序的上下文中特别有用:可能从标准输入读取、获取参数并写入标准输出。在这样的程序中,做完工作留下一个选择点,总是程序员的错误。

SWI-Prolog 提供deterministic/1,所以可以这样写:

(   deterministic(true)
->  true
;   fail
)

提出了另一种更便携的方法来实现同样的目的:

is_det(Goal, IsDet) :-
    setup_call_cleanup(true, Goal, Det=true),
    (   Det == true
    ->  IsDet = true
    ;   !,
        IsDet = false
    ).

不过,发生这种情况时抛出错误似乎很有用,但我不知道这个错误会是什么。我非常仔细地查看了ISO error terms,找不到可以明显描述这种情况的错误。

抛出错误确实更好,还是我应该失败?如果首选抛出错误,那么该错误会是什么?

编辑:我不知道该怎么做,因为特别是当涉及到副作用时,比如向标准输出写入一些东西,让副作用发生感觉非常错误,然后 em>失败。几乎有必要宁愿抛出一个异常。这还可以确定剩余的选择点是无害的(如果不需要的话)并捕获异常,然后写入标准错误或返回不同的退出代码。

但我真的不知道什么能正确描述异常,所以我不知道要抛出什么术语。

【问题讨论】:

  • “发生副作用并然后失败感觉非常错误”:我已经为这句话投了赞成票!
  • @mat:这就是 haskell 教的,安排你的副作用。如果您需要副作用,请将它们与您的推理分开。
  • @MiloslavRaus 将副作用分开是非常好的,但您最终必须承诺它们。永远延迟像输出这样的副作用是不切实际的。选择点确实有自己的方式潜入您的代码,尤其是在使用 DCG 时。 (只要您注意到它,就有许多描述良好的技术可以消除不需要的非确定性。)
  • 您需要一个新的错误术语,不知道如何调用它。 Related: call_semidet/1.
  • @Miloslav Raus:很高兴看到其他语言现在也提倡这种分离。

标签: exception error-handling prolog swi-prolog


【解决方案1】:

查看由 Ulrich Neumerkel 在 SWI-Prolog 邮件列表中提出的 call_semidet/1

call_semidet/1 - clean removal of choice-points

在其中,他提出:

call_semidet(目标):- ( call_nth(目标, 2) -> throw(error(mode_error(semidet,Goal),_)) ;一次(目标) )。

这个提议的mode_error是一个很好的开始。

实际上,它遵循其他错误:在这种情况下,模式semidet预期的,这反映在抛出的错误项中。

【讨论】:

  • 我不想编辑您的答案,但也许将链接添加到显示相同解决方案的answer here on SO 也会很有用。
  • 感谢您将其写成答案:我实际上已经从我链接的相当大的答案中错过了相关部分(您已用粗体表示),并且不知道此电子邮件线程, 任何一个。 call_nth/2 当然不适用于我的情况(副作用!),但这不是重点。
  • SO 答案的链接也很好。看吧,虽然 SWI 邮件列表在不久前是多么的酷!在 Ulrich 和 Richard 仍然参与的年份中,信噪比 高。
  • 好吧,有强烈意见的人加上这个非常遗憾的迁移到 googlegroups。如果有第二个问题的技术解决方案,那就太好了。就目前而言,没有gmail地址会让你成为二等网民。
  • 一系列糟糕的项目管理决策让我对 SWI-Prolog 几乎没有兴趣,但如果你提出这些问题,我希望你比我运气好,我会支持他们!
猜你喜欢
  • 2014-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-18
  • 2021-08-26
相关资源
最近更新 更多