Reputation:
This other question asks almost the same, but not quite. Rather, how do I demand that a goal succeeds deterministically (exactly once) and does not leave behind any choice points?
This is especially useful in the context of Prolog programs that are used as command-line tools: possibly read from standard input, take arguments, and write to standard output. In such a program, leaving a choice point after doing the work is invariably an error of the programmer.
SWI-Prolog offers deterministic/1
, so one could write:
( deterministic(true)
-> true
; fail
)
Another, more portable way to achieve the same was suggested:
is_det(Goal, IsDet) :-
setup_call_cleanup(true, Goal, Det=true),
( Det == true
-> IsDet = true
; !,
IsDet = false
).
However, it seems useful to throw an error when this happens, but I don't know what this error would be. I looked quite carefully through the ISO error terms and I could not find an error that would obviously describe this situation.
Is it indeed better to throw an error, or should I just fail? If throwing an error is to be preferred, what would that error be?
EDIT: I am not sure what to because especially when side effects are involved, like writing something to standard output, it feels very wrong to have the side effect happen and then fail. It is almost necessary to rather throw an exception. This makes it also possible to decide that the remaining choice point is harmless (if not desirable) and just catch the exception, then write to standard error or return a different exit code.
But I really have no idea what describes the exception properly, so I don't know what term to throw.
Upvotes: 3
Views: 185
Reputation: 40768
Check out call_semidet/1
as proposed by Ulrich Neumerkel on the SWI-Prolog mailing list:
call_semidet/1
- clean removal of choice-points
In it, he proposes:
call_semidet(Goal) :- ( call_nth(Goal, 2) -> throw(error(mode_error(semidet,Goal),_)) ; once(Goal) ).
This proposed mode_error
is a very good start.
In spirit, it follows the other errors: In this case, mode semidet
is expected, and this is reflected in the thrown error term.
Upvotes: 3