Erroneous, failure, semidet, det, multi

I have the following program which does a run-time check of various determinacies. I believe they all work, but the version of multi has a seemingly unnecessary additional call. Is there some way to avoid this?

errorneous(Module,Goal) :-
    throw(determinism_error(Module:Goal,erroneous)).

failure(Module,Goal) :-
    call(Module:Goal),
    throw(determinism_error(Module:Goal,failure)).

det(Module,Goal) :-
    (   call_cleanup(Module:Goal, Det=true),
        (   Det == true
        ->  true
        ;   throw(detreminism_error(Module:Goal, det))
        )
    ->  true
    ;   throw(detreminism_error(Module:Goal, det))
    ).

semidet(Module,Goal) :-
    (   call_cleanup(Module:Goal, Det=true),
        (   Det == true
        ->  true
        ;   throw(detreminism_error(Module:Goal, semidet))
        )
    ->  true
    ;   fail
    ).

    
multi(Module,Goal) :-
    (   \+ call(Module:Goal)
    ->  throw(determinism_error(Module:Goal,multi))
    ;   call(Module:Goal)
    ).

You have a few typos (e.g., “detreminism” instead of “determinism”).
Also, it’s better to do a throw like this: throw(error(determinism_error(Module:Goal, multi), _)) so that you can get some nice default handling, e.g., displaying a traceback.

As to your multi/1 … perhaps setup_call_catcher_cleanup/4 has what you need?

See *->/2

1 Like

Haha, oops! Thanks for picking that up.

It seems to me that the problem with *-> is that I’ll end up in the ‘;’ branch regardless of whether there was a solution or not. How can I record that there was at some point a success (or no success)? Seems like I need access to something extralogical - I’ll have a think about how setup_call_catcher_cleanup/4 might be used…

No. You only end in the “;” branch if the test has no solutions.

1 Like

Indeed! Silly me!