Your question is about two different parts. First, catch/3 can be used to handle this situation. And then the timeout mechanism itself.
Catching bugs and exceptions with catch/3
Generally speaking, the most idiomatic way to use catch/3 like this:
..., catch((R = success, Goal), Pat, R = error(Pat)), ...
However, catching all errors / exceptions often leads to error prone programs because a serious unexpected error can be hidden.
In your particular case, you want to catch only one pattern, like this:
..., catch((R = success, call_with_time_limit(Time,Goal)), time_limit_exceeded, R = timeout ), ...
Note that testing unconfirmed variables with var(Pat) can be an easy-to-use error source.
Processing Timeouts
Different systems offer several interfaces. But the most fundamental question is what you really want to achieve. Do you want to limit real-time time, processor time, or just resources?
time_out/3 in library(timeout) is probably the most advanced one that was originally developed for SICStus Prolog around 1992. There are several compatible implementations in SWI and YAP. However, SWI and YAP cannot handle nested cases. And SWI does not limit CPU time. Interface:
time_out(:Goal_0, +TimeMs, -Result)
call_with_time_limit/3 is a rather peculiar built-in SWI that does not comply with the general conventions for built-in modules. In addition, he only calls his goal once(Goal_0) . I would rather not.
call_with_inference_limit/3 , which is currently only available in recent versions of SWI and uses similar conventions as time_out/3 . This limits the number of pins, not processor time. Thus, it is well suited for detecting programmer cycles, but not suited to your task.
wait_for_input/3 may be an option for you if your timeouts are only related to reading data.