Ok, let's get creative... You essentially need a way to remember (across backtracking) that the If-condition had at least one solution. Dynamic predicates are a no-no for me, but are there any alternatives? Well, ISO-Prolog defines one kind of anonymous object, the stream-term, which could be (ab)used to implement the non-backtrackable flag in this rather elegant way:
if(If, Then, Else) :-
open(., read, S),
(
If,
close(S, [force(true)]),
Then
;
catch(close(S), error(existence_error(stream,_),_), fail), % fail if already closed
Else
).
We close the stream to indicate that If
had a solution, and this is then detected by the close-attempt in the else branch. This works perfectly and leak-free in a system like ECLiPSe. However, many systems (including XSB) re-use the identifiers of closed streams (which is not forbidden by ISO), making this solution non-portable.
But wait, streams have a position property, which can be set, and which retains its value across backtracking! Using this trick, the following works on XSB:
if(If, Then, Else) :-
% open('ReadableAndNonemptyFile', read, S), % general ISO
open(atom(a), read, S), % XSB (needs no file)
stream_property(S, position(Zero)),
get_char(S, _),
(
catch(If, Ball, (close(S),throw(Ball))),
set_stream_position(S, Zero),
Then
; stream_property(S, position(Zero)) ->
close(S),
fail
;
close(S),
Else
).
Sadly, the open(atom(...),...)
feature is XSB-specific, for strict ISO-Prolog you need a dummy file...
if/3
for this, like SICStus does. Also, why do you need this construct? Note that you do not get monotonicity with it. It has similar flaws like Prolog style negation has. – Plagiarize