Exception 确保谓词决定性地成功

Exception 确保谓词决定性地成功,exception,error-handling,prolog,swi-prolog,Exception,Error Handling,Prolog,Swi Prolog,要求几乎相同,但不完全相同。相反,我如何要求一个目标决定性地成功(恰好一次),并且不留下任何选择点 这在用作命令行工具的Prolog程序环境中特别有用:可能从标准输入读取、获取参数以及写入标准输出。在这样的程序中,在完成工作后留下一个选择点总是程序员的错误 SWI Prolog提供了以下内容: ( deterministic(true) -> true ; fail ) 有人提出了实现这一目标的另一种更便捷的方法: is_det(Goal, IsDet) :- setu

要求几乎相同,但不完全相同。相反,我如何要求一个目标决定性地成功(恰好一次),并且不留下任何选择点

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

SWI Prolog提供了以下内容:

(   deterministic(true)
->  true
;   fail
)
有人提出了实现这一目标的另一种更便捷的方法:

is_det(Goal, IsDet) :-
    setup_call_cleanup(true, Goal, Det=true),
    (   Det == true
    ->  IsDet = true
    ;   !,
        IsDet = false
    ).
然而,发生这种情况时抛出一个错误似乎很有用,但我不知道这个错误是什么。我非常仔细地看了一遍,找不到一个可以明显描述这种情况的错误

还是我应该失败呢?如果抛出错误是首选,那么该错误是什么


编辑:我不确定该怎么办,因为特别是当涉及到副作用时,比如在标准输出中写入内容,让副作用发生然后失败感觉非常错误。几乎有必要抛出异常。这也使得确定剩余的选择点是无害的(如果不需要的话)并捕获异常,然后写入标准错误或返回不同的退出代码成为可能


但我真的不知道是什么恰当地描述了异常,所以我不知道该抛出什么术语。

查看Ulrich Neumerke在SWI Prolog邮件列表中提出的
调用semidet/1

他在报告中提出:

call_semidet(Goal) :- ( call_nth(Goal, 2) -> throw(error(mode_error(semidet,Goal),_)) ; once(Goal) ). 呼叫semidet(目标):- (呼叫第n个(目标2) ->投掷(错误(模式错误(半决赛,进球),) ;一次(目标) ). 这一拟议的
模式错误
是一个很好的开端


在精神上,它遵循了其他错误:在这种情况下,模式
semidet
预期的,这反映在抛出的错误术语中。

“发生副作用然后失败感觉非常错误”:我已经为这句话投票了@马特:这就是哈斯克尔教授的,计划好你的副作用。如果你需要副作用,就把它们和你的推理分开。@MiloslavRaus把副作用分开是很好的,但你最终还是要致力于它们。永远推迟像输出这样的副作用是不现实的。选择点确实有潜入代码的方式,特别是当使用DCG时。(只要你注意到,有许多被很好地描述的技术可以消除不必要的非确定性。)你需要一个新的错误术语,不知道如何称呼它@米洛斯拉夫·劳斯:很高兴看到其他语言现在也提倡这种分离。我不想编辑您的答案,但也许添加到显示相同解决方案的链接也很有用。谢谢您将此作为一个答案写下来:我实际上错过了相关部分(您以粗体显示)从我链接的相当大的答案来看,我也不知道这个电子邮件线程。
call\n/2
当然对我的情况不起作用(副作用!),但这不是重点。SO答案的链接也很好。瞧,不久前SWI邮件列表是多么酷!在Ulrich和Richard仍然参与的那些年里,信噪比要高得多。好吧,有强烈意见的人加上这一令人遗憾的谷歌集团的举动。如果能从技术上解决第二个问题,那就太好了。就目前而言,没有gmail地址让你成为了二等网民。一系列糟糕的项目管理决策让我对SWI Prolog失去了兴趣,但如果你提出这些问题,我希望你比我幸运,我会支持他们!