Вот мое дополнение к использованию ^
в setof/3
и bagof/3
.
Предварительное примечание:
Лично я считаю семантику ^
неудачной, потому что она выглядит так, как если бы это была «экзистенциальная квантификация» и даже иногда описывается как таковая (например: Пролог GNU, библиотека SWI-Prolog(yall)), но на самом деле это НЕ. Избегайте этой ошибки, вместо этого напишите отдельный предикат, который будет вызываться setof/3
и bagof/3
. ISO Prolog-2, если он когда-либо появится, должен действительно очистить это.
Начнем с обзора изображения ASCII:
Clause-wide variable
|
|
+------------------------+------------------------+
| |
| Clause-wide variables |
| that are collected via the |
| template at arg-position 1 by |
| setof/3 (NOT local to setof/3) |
| thus can be constrained elsewhere |
| in the clause (possibly accidentally) |
| | |
| | |
| +-+--------+----------+-+ |
| | | | | |
| | | | | |
get_closed_set(Set,K) :- setof( [X,Y] , P^R^search(P,R,X,Y,K) , Set).
| | | | | |
| <-------------------> Goal expression
| | | | | |
| | | | | |
+---------------------------------------+-----+
| | | | |
| | | | |
+-+----+---+-+ Clause-wide variable.
| Backtracking over this
| is done by the caller
| of get_closed_set/2.
|
Variables marked as "free for
backtracking if fresh".
This is NEARLY the same as "being
local to the goal expression" or
"being existentially quantified."
Backtracking over these is done by setof/3.
If these appear elsewhere in the clause,
they be constrained (possibly accidentally)!
Тестовые примеры ожидаемого поведения
search(1,n,a,g).
search(2,m,a,g).
search(2,m,a,j).
search(1,m,a,j).
search(3,w,a,j).
search(3,v,a,j).
search(2,v,b,g).
search(3,m,b,g).
search(5,m,b,g).
search(2,w,b,h).
% ===
% HATTY EXPRESSIONS ("CLOSED EXPRESSIONS")
% ===
% If P and R do not appear anywhere else than in the goal expression.
% "P^R^" (not quite) closes off variables P,R: they are not (not quite)
% invisible outside of the goal expression "P^R^search(P,R,X,Y)"
get_closed_set(Set) :- setof( [X,Y] , P^R^search(P,R,X,Y) , Set).
get_closed_bag(Bag) :- bagof( [X,Y] , P^R^search(P,R,X,Y) , Bag).
% The above is the same as this (which I recommend for clarity and
% to avoid annoying bug searches):
indirect_search(X,Y) :- search(_P,_R,X,Y).
get_closed_set_indirect(Set) :- setof( [X,Y] , indirect_search(X,Y) , Set).
get_closed_bag_indirect(Bag) :- bagof( [X,Y] , indirect_search(X,Y) , Bag).
% ===
% NONHATTY EXPRESSIONS ("OPEN EXPRESSIONS")
% ===
get_open_set(Set,P,R) :- setof( [X,Y] , search(P,R,X,Y) , Set).
get_open_bag(Bag,P,R) :- bagof( [X,Y] , search(P,R,X,Y) , Bag).
% ===
% TESTING
% ===
:- begin_tests(hat_operator).
test(clo_set) :- get_closed_set(Set),
format("Closed Set:\n ~q\n",[Set]),
Set = [[a,g],[a,j],[b,g],[b,h]].
test(clo_bag) :- get_closed_bag(Bag),
format("Closed Bag:\n ~q\n",[Bag]),
Bag = [[a,g],[a,g],[a,j],[a,j],[a,j],[a,j],[b,g],[b,g],[b,g],[b,h]].
test(clo_set_ind) :- get_closed_set_indirect(Set),
format("Closed Set, indirect:\n ~q\n",[Set]),
Set = [[a,g],[a,j],[b,g],[b,h]].
test(clo_bag_ind) :- get_closed_bag_indirect(Bag),
format("Closed Bag, indirect:\n ~q\n",[Bag]),
Bag = [[a,g],[a,g],[a,j],[a,j],[a,j],[a,j],[b,g],[b,g],[b,g],[b,h]].
test(opn_set) :- bagof(solution(Set,P,R), get_open_set(Set,P,R), OuterBag),
format("Bag for get_open_set/3:\n ~q\n",[OuterBag]).
test(opn_bag) :- bagof(solution(Bag,P,R), get_open_bag(Bag,P,R), OuterBag),
format("Bag for get_open_bag/3:\n ~q\n",[OuterBag]).
:- end_tests(hat_operator).
rt :- run_tests(hat_operator).
Когда мы запускаем rt
, ничего неожиданного не происходит, мы как Фонзи с кванторами существования:
Closed Set: [[a,g],[a,j],[b,g],[b,h]]
Closed Bag: [[a,g],[a,g],[a,j],[a,j],[a,j],[a,j],
[b,g],[b,g],[b,g],[b,h]]
Closed Set, indirect: [[a,g],[a,j],[b,g],[b,h]]
Closed Bag, indirect: [[a,g],[a,g],[a,j],[a,j],[a,j],[a,j],
[b,g],[b,g],[b,g],[b,h]]
Bag for get_open_set/3: [solution([[a,j]],1,m),solution([[a,g]],1,n),
solution([[a,g],[a,j]],2,m),solution([[b,g]],2,v),
solution([[b,h]],2,w),solution([[b,g]],3,m),
solution([[a,j]],3,v),solution([[a,j]],3,w),
solution([[b,g]],5,m)]
Bag for get_open_bag/3: [solution([[a,j]],1,m),solution([[a,g]],1,n),
solution([[a,g],[a,j]],2,m),solution([[b,g]],2,v),
solution([[b,h]],2,w),solution([[b,g]],3,m),
solution([[a,j]],3,v),solution([[a,j]],3,w),
solution([[b,g]],5,m)]
Пробовать поведение для менее очевидных выражений
Возможно, вам придется запустить это, чтобы увидеть больше вывода списка (в случае SWI-Prolog):
set_prolog_flag(answer_write_options,[max_depth(100)]).
set_prolog_flag(debugger_write_options,[max_depth(100)]).
Синглтоны в выражении цели
Если вы введете следующее, Prolog правильно предупредит об "одноэлементных переменных P, R". Хорошо.
get_open_set(Set) :- setof([X,Y],search(P,R,X,Y),Set).
Головные уборы вне комплекта/3 или мешка/3
Это принято, и ему можно было бы придать значение, но Пролог будет искать процедуру ^/2
при вызове и скажет, что "^/2 может появиться только как второй аргумент setof/3 и bagof/3" . Хорошо.
get_outerly_closed_set(Set) :- P^R^setof([X,Y],search(P,R,X,Y),Set).
Возможное значение вышеизложенного может быть совершенно обыденным:
get_outerly_closed_set(Set) :- close_it_off(Set).
close_it_off(Set) :- setof([X,Y],search(_P,X,_R,Y),Set).
Закрытая переменная, используемая в другом месте пункта: Проблемно!
Теперь мы попадаем на территорию «неудачи семантики»: Пролог не рассматривает внешнее P
как переменную, отличную от P
в P^
. Вот почему P^
НЕ означает "∃P такое, что":
get_closed_set_weird_1(Set,P) :-
setof( [X,Y] , P^R^search(P,R,X,Y) , Set),
format("P=~q\n",[P]).
?- get_closed_set_weird_1(Set,P).
P=_14996
Set = [[a, g], [a, j], [b, g], [b, h]].
?- get_closed_set_weird_1(Set,1).
P=1
Set = [[a, g], [a, j]].
Вариация закрытой переменной, используемая в другом месте пункта: Проблемно!
Никаких предупреждений не возникает, если вы пишете такую вещь:
get_closed_set_weird_2(Set) :-
setof( [X,Y,P], P^R^search(P,R,X,Y), Set).
?- get_closed_set_weird_2(Set).
Set = [[a, g, 1], [a, g, 2], [a, j, 1], [a, j, 2], [a, j, 3], ...
Фактически, P^
игнорируется. Вышеупомянутое аналогично:
get_closed_set_weird_2e(Set) :-
setof( [X,Y,P], R^search(P,R,X,Y), Set).
Свободная переменная для диапазона, используемая в другом месте в предложении: Проблематично!
Это вполне ожидаемое поведение, но случайное прочтение setof([X,Y], ...
может привести к мысли, что [X,Y]
являются свободными переменными, в пределах которых setof/3
колеблется. Это не так: [X,Y]
— это просто шаблон, а X
и Y
на самом деле являются переменными всего предложения, которые могут быть ограничены в другом месте:
get_closed_set_weird_2(Set,X) :-
setof( [X,Y], P^R^search(P,R,X,Y) , Set),
format("X=~q\n",[X]).
?- get_closed_set_weird_2(Set,X).
X=_20346
Set = [[a, g], [a, j], [b, g], [b, h]].
?- get_closed_set_weird_2(Set,b).
X=b
Set = [[b, g], [b, h]].
Вышесказанное было бы более ясным, поскольку
get_closed_set_weird_2c(Set,V) :-
setof( [V,Y], close_it_off(V,Y), Set),
format("V=~q\n",[V]).
close_it_off(X,Y) :- search(_P,_R,X,Y).
?- get_closed_set_weird_2c(Set,V).
V=_21682
Set = [[a, g], [a, j], [b, g], [b, h]].
но обратите внимание, что это абсолютно не то же самое, что здесь, где мы возвращаемся к V
вне setof/3
:
get_closed_set_weird_2x(Set,V) :-
setof( [X,Y], close_it_off(V,X,Y), Set),
format("V=~q\n",[V]).
close_it_off(V,X,Y) :- V=X,search(_P,_R,X,Y).
?- get_closed_set_weird_2x(Set,V).
V=a
Set = [[a, g], [a, j]], V = a ;
V=b
Set = [[b, g], [b, h]], V = b.
Должны быть приемлемые обозначения
Хотелось бы иметь четкий способ указать, какие переменные целевого выражения видимы за пределами целевого выражения, а какие нет и какие из них следует ранжировать.
Как насчет этого:
- Если в начале выражения цели есть
λX.
, то X
видно вне выражения цели. Любое X
в другом месте в предложении является тем же самым X
.
- Если в начале выражения цели есть
∃X.
, то X
невидимо вне выражения цели. Любое X
в другом месте пункта является другим X
(затем редактор предложит вам продолжить переименование).
- Любое
X
, которое появляется в выражении цели без предшествующего λX.
или ∃X.
, является ошибкой компилятора.
- Вы можете поместить все, что хотите, в шаблон, лямбда-ред, экзистенциализированный или глобальный.
- Вызванная цель охватывает любые переменные, которые она считает свежими: либо свежие, отображаемые как
λX.
, и любые переменные, отображаемые как ∃X.
.
(Не жалуйтесь на строчную букву x
выше, она просто так выглядит. λX. ∃X. Xx
)
person
David Tonhofer
schedule
14.04.2020
current_op(200,fy,-).
- person false   schedule 12.11.2013