Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
669 views
in Technique[技术] by (71.8m points)

prolog - How to safely temporarily change the occurs check flag?

I am using the following code to temporarily change the occurs check flag, where G is a goal that doesn't create any delayed goals:

with_occurs_check(G) :-
   current_prolog_flag(occurs_check, F),
   setup_call_cleanup(
      set_prolog_flag(occurs_check, true),
      G,
      set_prolog_flag(occurs_check, F)).

The below is a desired aspect of with_occurs_check/1, since we want all backtracking into the goal G work with the occurs check flag set to true. Also preferably only once a choice point is created, this is seen in SWI-Prolog that ";" is only asked once and not twice:

?- with_occurs_check((X=1;current_prolog_flag(occurs_check, F), X=2)).
X = 1 ;
X = 2,
F = true.   %%% desired

But there is a caveat. The above doesn't really work when G is non-deterministic. If G has an exit port with remaining choice points, setup_call_cleanup/3 will not call its cleanup. So the occurs check flag change will leak into the continuation:

?- with_occurs_check((X=1;X=2)), current_prolog_flag(occurs_check, F).
X = 1,
F = true ;   %%% not desired, update leaking
X = 2,
F = false.   %%% desired

Is there a safer way to change the occurs check temporarily?

question from:https://stackoverflow.com/questions/66045332/how-to-safely-temporarily-change-the-occurs-check-flag

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Maybe revert the occurs check also after G succeeds ?

with_occurs_check(G) :-
   current_prolog_flag(occurs_check, F),
   setup_call_cleanup(
      set_prolog_flag(occurs_check, true),
      (G, set_prolog_flag(occurs_check, F)),
      set_prolog_flag(occurs_check, F)).

test run:

?- with_occurs_check((X=1;X=2)), current_prolog_flag(occurs_check, F).
X = 1,
F = false ;
X = 2,
F = false.

Update after reading comments so that occurs_check continue to be true upon backtracking:

with_occurs_check(G) :-
   current_prolog_flag(occurs_check, F),
   setup_call_cleanup(
      set_prolog_flag(occurs_check, true),
      (G, with_occurs_check1(F)),
      set_prolog_flag(occurs_check, F)).

with_occurs_check1(F):-
  set_prolog_flag(occurs_check, F).
with_occurs_check1(_):-
  set_prolog_flag(occurs_check, true),
  fail.

Sample run:

?- with_occurs_check((X=1;current_prolog_flag(occurs_check, F), X=2)), current_prolog_flag(occurs_check, F2).
X = 1,
F2 = false ;
X = 2,
F = true,
F2 = false ;
false.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...