修正了call_with_time_limit / call_with_inference_limit

时间:2019-02-13 19:48:51

标签: prolog meta-predicate

我正在尝试根据调用callto_status(Goal, Status)的结果定义一个始终成功并统一Status的关系Goal(换句话说,我想实现{{1}的简化版本) }。我的实现使用SWI的call_with_inference_limit/3call_with_inference_limit/3具有相同的接口(在这种情况下也应使其起作用)。 call_with_time_limit/3的实现不会回溯,因此我认为最好不要给人以为目标报告答案的印象。

为了便于阅读,我介绍了辅助谓词call_with_..._limit。它处理成功和超时的情况,但否则失败。

derivable_st

主谓词环绕% if Goal succeeds, succeed with Status = true, % if Goal times out, succeed with Status = timeout % if Goal fails, fail derivable_st(Goal, Status) :- T = 10000, % set inference limit % copy_term(Goal, G), % work on a copy of Goal, we don't want to report an answer substitution call_with_inference_limit(G, T, R), % actual call to set inference limit ( R == ! -> Status = true % succeed deterministically, status = true ; R == true -> Status = true % succeed non-deterministically, status = true ; ( R == inference_limit_exceeded % timeout -> ( !, % make sure we do not backtrack after timeout Status = timeout % status = timeout ) ; throw(unhandled_case) % this should never happen ) ). 并处理失败情况和可能引发的异常(如果有)。我们可能希望选择堆栈溢出(在推理限制过高的情况下发生),但是现在我们只报告任何异常。

derivable_st

谓词适用于一些简单的测试用例:

% if Goal succeeds, succeed with Status = true,
% if Goal times out, succeed with Status = timeout
% if Goal fails, succeed with Status = false
% if Goal throws an error, succeed with Status = exception(The_Exception)
% Goal must be sufficiently instantiated for call(Goal) but will stay unchanged
callto_status(Goal, Status) :-
    catch((  derivable_st(Goal, S)            % try to derive Goal
          -> Status = S                       % in case of success / timeout, pass status on
          ;  Status = false                   % in case of failure, pass failure status on, but succeed
          ),
          Exception,
          Status = exception(Exception)       % wrap the exception into a status term
    ).

我现在的问题有点含糊:这个谓词是否符合我的要求?您是否看到任何错误/改进点?感谢您的投入!

编辑:如@false所建议,将?- callto_reif( length(N,X), Status). Status = true. ?- callto_reif( false, Status). Status = false. ?- callto_reif( (length(N,X), false), Status). Status = timeout. 注释掉

1 个答案:

答案 0 :(得分:1)

这是一个较短的解决方案:

callto_status(Goal, Status) :-
    call_with_inference_limit(Goal, 10000, Status0),
    (Status0 = ! -> !, Status = true; Status = Status0).
callto_status(_, false).

您会看到原始的有用之处!状态是为了避免不必要的选择点:

?- callto_status(member(X,[1,2,3]), Y).
X = 1,
Y = true 
X = 2,
Y = true 
X = 3,
Y = true.

?- callto_status(fail, Y).
Y = false.

您当然也可以仅将Status0 = ! -> !, Status = true替换为Status0 = ! -> Status = true。然后,您将始终获得剩余的选择点:

?- callto_status(member(X,[1,2,3]), Y).
X = 1,
Y = true 
X = 2,
Y = true 
X = 3,
Y = true 
Y = false.

从问题中不清楚您到底想要什么。