# Catch/throw/recover -- until its suceeds

**URL:** <https://swi-prolog.discourse.group/t/catch-throw-recover-until-its-suceeds/288>\
**Category:** Help!\
**Created:** [February 17, 2019, 2:40am UTC](https://swi-prolog.discourse.group/t/catch-throw-recover-until-its-suceeds/288 "2019-02-17T02:40:57Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![grossdan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/grossdan/32/23_2.png) [@grossdan](https://swi-prolog.discourse.group/u/grossdan)\
**Post date:** [February 17, 2019, 2:40am UTC](https://swi-prolog.discourse.group/t/catch-throw-recover-until-its-suceeds/288/1 "2019-02-17T02:40:57Z")

</div>

I am reviewing again the catch / throw / recover predicates.

I need to write a predicate that may need recovery actions repeatedly to occur.

So, a first call, could throw an exception, which is then handled by a recover action, which eventually would call the predicate again, and this second call (attempt) which then again could throw an exception, requiring a recover, and so on, until the call succeeds without exception.

Can this be achieved with one catch/throw/recover or do i need to somehow recursively recall the predicate with separate catch calls.

thanks,

Dan

---

<div class="post-metadata">

**Author:** ![zhCX](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/zhcx/32/151_2.png) [@zhCX](https://swi-prolog.discourse.group/u/zhCX)\
**Post date:** [March 23, 2019, 3:12am UTC](https://swi-prolog.discourse.group/t/catch-throw-recover-until-its-suceeds/288/2 "2019-03-23T03:12:30Z")

</div>

The following code demonstrates such functionality  
also including a count which might be useful  
during recover when deciding to continue or give up .

~~~~~~~~%&ZHcx;.~~~~~~~~

```auto
/*
?- demo .
question about recover(user:task,1,ball(oops)) .
continue [yn] ? y

question about recover(user:task,2,ball(oops)) .
continue [yn] ? |: y

question about recover(user:task,3,ball(oops)) .
continue [yn] ? |: n

gaveup(user:task,3,ball(oops)) .
true.
*/

```

```auto
:- meta_predicate try(:,:,:) .

/*
Try to perform the goal supplied by _try_ ;
if that _try_ goal does throw a ball ,
then call _recover_ with 1st argument the _try_ and 2nd argument the _count_ and 3rd argument the _ball_ .
If that _recover_ does evaluate ``true`` then call the _try_ goal again ;
otherwise if that _recover_ does evaluate false
then call _gaveup_ with 1st argument the _try_ and 2nd argument the _count_ and 3rd argument the _ball_ .
*/

try(_try_,_recover_,_gaveup_) :-
(
    try(_try_,_recover_,_gaveup_,0)
) .

try(_try_,_recover_,_gaveup_,_count_) :-
(
    _COUNT_ is _count_ + 1 ,
    catch(_try_,_ball_,try(_try_,_recover_,_gaveup_,_COUNT_,_ball_))
) .

:- meta_predicate try(:,:,:,-) .

try(_try_,_recover_,_gaveup_,_count_,_ball_) :-
(
    call(_recover_,_try_,_count_,_ball_) ->
    try(_try_,_recover_,_gaveup_,_count_) ;
    call(_gaveup_,_try_,_count_,_ball_)
) .

```

```auto
demo :-
(
    try(task,recover,gaveup)
) .

task :-
(
    throw(ball(oops))
) .

:- meta_predicate recover(:,-,-) .

recover(_try_,_ball_,_count_) :- repeat ,
(
    format('~Nquestion about ~q .',[recover(_try_,_ball_,_count_)]) ,
    format('~Ncontinue [yn] ? ',[]) ,
    flush_output ,
    get(_code_) ,
    (
        (_code_ = 0'y ; _code_ = 0'Y) -> ! , true ;
        (_code_ = 0'n ; _code_ = 0'N) -> ! , false ;
        false
    )
) .

:- meta_predicate gaveup(:,-,-) .

gaveup(_try_,_ball_,_count_) :-
(
    format('~N~q .',[gaveup(_try_,_ball_,_count_)])
) .

```

---

<div class="post-metadata">

**Author:** ![PasiK](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/pasik/32/84_2.png) [@PasiK](https://swi-prolog.discourse.group/u/PasiK)\
**Post date:** [March 24, 2019, 7:14pm UTC](https://swi-prolog.discourse.group/t/catch-throw-recover-until-its-suceeds/288/3 "2019-03-24T19:14:18Z")

</div>

Hi zhCX

Here is a proposal for you that I have used myself, I made it from my code quickly, so it might have problems. You will have to edit it for your needs and test it.

Call tst/0 and after 5 exceptions it throws a ‘really bad situation’

The exception catcher receives also the code that caused an exception and that code is re-used to call again. Prolog has the ability to pass code around.

This example worked on my Windows 10 and SWI-Prolog version (threaded, 64 bits, version 8.1.0).

```auto
exc( 'guru meditation',(_=5, _Code)):-
    !,
    throw('really bad situation').

exc( 'guru meditation',(_=Number,Code)):-

   %recovering code needs to be but here

    succ(Number,SNumber),
    W2= (_=SNumber,Code),

    catch( W2,Exception,exc(Exception,W2)).

tst:-
    W=(throw('guru meditation'),writeln(hello)), %code with an exception
    catch( W,Exception,exc(Exception,( _Number=0,W))).

```
