Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

catch/3 and call_with_time_limit/2 predicates in SWI-Prolog

I want to use

catch(:Goal, +Catcher, :Recover)

where Goal is

call_with_time_limit(+Time, :Goal)

It's messed up and I can't find the right way to know when one of the above happened:

1) Goal stopped because of time out.

2) Goal failed (it's suppose to fail sometimes).

I tried:

(catch(call_with_time_limit(Time, Goal), Catcher, Recover) ->
(ground(Catcher), Catcher = time_limit_exceeded), **TIMEOUT ACTIONS**)
;
(**SUCCESS ACTIONS**))
;
**FAILURE ACTIONS**
)

* EDIT *

Pattern:

I use the following pattern:

((catch(call_with_time_limit(6,goal),
    Exception,
    true),(var(Exception);Exception=time_limit_exceeded))
->
    (var(Exception) -> writeln(succ) ; writeln(timeout))
;
    writeln(fail)
).

That pattern doesn't work for 4 or more seconds - it just ignores the request for timeout.

like image 974
Mockingbird Avatar asked May 27 '14 23:05

Mockingbird


2 Answers

Your question concerns two different parts. First, the way how catch/3 can be used to handle such a situation. And then the timeout mechanism itself.

Catching errors and exceptions with catch/3

Generally speaking, the most idiomatic way to use catch/3 is like so:

   ...,
   catch((R = success, Goal), Pat, R = error(Pat)),
   ...

However, catching all errors/exceptions leads often to error-prone programs since a serious, unexpected error might be masked out.

In your particular case you want to catch a single pattern only, thus:

   ...,
   catch((R = success, call_with_time_limit(Time,Goal)),
          time_limit_exceeded,
          R = timeout ),
   ...

Please note that testing for uninstantiated variables using var(Pat) might be an easy-to-miss source of errors.

Handling timeouts

There are several interfaces offered in various systems. But the most fundamental question is what you actually want to achieve. Do you want to limit realtime, CPU time, or just resources?

time_out/3 in library(timeout) is probably the most advanced which was originally developed for SICStus Prolog about 1992. There are somewhat compatible implementations in SWI and YAP. However, SWI and YAP cannot handle nested cases. And SWI does not limit CPU-time. The interface is:

time_out(:Goal_0, +TimeMs, -Result)

call_with_time_limit/3 is a rather idiosyncratic built-in of SWI which does not conform to the common conventions for built-ins. Also, it calls its goal as once(Goal_0) only. I'd rather not.

call_with_inference_limit/3 this is currently present only in recent versions of SWI and uses similar conventions as time_out/3. It limits the number of inferences rather than CPU-time. It is thus well suited to detect programmer's loops but might not be suited for your task.

wait_for_input/3 might be an option for you should your timeouts be only related to reading data.

like image 128
false Avatar answered Nov 10 '22 01:11

false


Try the pattern:

(   catch(call_with_time_limit(Time,Goal), Error, true) ->
    (   var(Error) ->
        % success actions
    ;   % error actions
    )
;   % failure actions
).
like image 39
Paulo Moura Avatar answered Nov 10 '22 03:11

Paulo Moura