Как безопасно временно изменить флаг проверки событий?

Я использую следующий код, чтобы временно изменить флаг проверки возникновения, где G — цель, которая не создает никаких отложенных целей:

      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)).

Ниже приведен желательный аспект with_occurs_check/1, поскольку мы хотим, чтобы все возвраты к цели G работали с флагом проверки возникновения, установленным в значение true. Также предпочтительно только после создания точки выбора, это видно в SWI-Prolog, что ";" спрашивается только один раз, а не дважды:

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

Но есть предостережение. Вышеприведенное на самом деле не работает, когда G недетерминирован. Если у G есть выходной порт с оставшимися точками выбора, setup_call_cleanup/3 не будет вызывать его очистку. Таким образом, изменение флага проверки происходит, и оно просочится в продолжение:

      ?- 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

Есть ли более безопасный способ временно изменить проверку событий?

1 ответ

Может быть, отменить проверку возникновения и после того, как G завершится успешно?

      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)).

тестовый забег:

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

Обновите после прочтения комментариев, чтобы при откате и при возврате значение exists_check оставалось верным:

      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.

Пример запуска:

      ?- 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.
Другие вопросы по тегам