确保谓词确定性地成功

Ensuring that a predicate succeeds deterministically

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

这在用作命令行工具的 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,但找不到明显描述这种情况的错误。

抛出错误确实更好,还是直接失败?如果抛出错误是首选,那么错误是什么?

编辑:我不确定该怎么做,因为特别是当涉及到副作用时,比如向标准输出写东西,让副作用发生感觉很不对 然后失败。抛出异常几乎是必要的。这也可以决定剩余的选择点是无害的(如果不需要的话)并且只捕获异常,然后写入标准错误或 return 不同的退出代码。

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

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

call_semidet/1 - clean removal of choice-points

在其中,他提出:

call_semidet(Goal) :-
   (  call_nth(Goal, 2)
   -> throw(error(mode_error(semidet,Goal),_))
   ;  once(Goal)
   ).

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

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