Моделирование exists_check=ошибка в SICStus Prolog
Оказывается, что SICStus Prolog не имеет флага Prolog exists_check. По крайней мере, мы не смогли найти его, и здесь выдается сообщение об ошибке:
/* SICStus 4.6.0 (x86_64-win32-nt-4) */
?- set_prolog_flag(occurs_check, true).
Domain error in argument 1 of set_prolog_flag/2
Кажется, что значение "true" не так уж и проблема, критические унификации могут быть реализованы с помощью существующих встроенных
unify_with_occurs_check/2
. Интересным значением флага Prolog exists_check является значение "ошибка".
Как можно реализовать предикат
unify_with_occurs_check_and_error/2
? Обратите внимание, что решение для unify_with_occurs_check_and_error/2 должно вести себя как unify_with_occurs_check/2, то есть не запускать переменные с атрибутами.
Вот пример использования флага Пролога, если он присутствует:
?- set_prolog_flag(occurs_check, error).
true.
?- X = f(X).
ERROR: ...
И это то, что можно было бы сделать в SICStus Prolog:
?- unify_with_occurs_check_and_error(X, f(X)).
ERROR: ...
1 ответ
Адаптировал код отсюда и получил следующее решение:
unify_with_error(X, Y) :- var(X), var(Y), !, X = Y.
unify_with_error(X, Y) :- var(X), !, must_notin(X, Y), X = Y.
unify_with_error(X, Y) :- var(Y), !, must_notin(Y, X), X = Y.
unify_with_error(X, Y) :- functor(X, F, A), functor(Y, G, B),
F/A = G/B,
X =.. [_|L],
Y =.. [_|R],
maplist(unify_with_error, L, R).
must_notin(X, Y) :-
term_variables(Y, L),
maplist(\==(X), L), !.
must_notin(X, Y) :-
throw(error(occurs_check(X, Y),_)).
Кажется, работает и не мешает атрибутированным переменным:
/* SICStus 4.6.0 (x86_64-win32-nt-4) */
?- unify_with_error(X, f(X)).
error(occurs_check(_413,f(_413)),_409)
?- freeze(X, throw(ball)), unify_with_error(X, f(X)).
error(occurs_check(_413,f(_413)),_409)