bagof/3 непредсказуемо
Я сбит с толку следующими результатами. Я использую SWI-Prolog.
?- bagof(Q, (Q=A, (A=[a,_] ; A=[_,b])), X).
A = [_G16898, b],
X = [[_G16898, b]] ;
A = [a, _G16892],
X = [[a, _G16892]].
Заметить, что [a,_]
а также [_,b]
не объединены, чтобы дать ответ A = [a,b], X=[[a,b],[a,b]]
,
Теперь давайте попробуем то же самое с арифметическими ограничениями:
?- bagof(Q, (Q=A, (A in 1..5 ; A in 3..8)), X).
X = [A, A],
A in 3..5.
Как ни странно, на этот раз арифметические ограничения взяты вместе, но нет ответов A in 1..5, X=[A]
а также A in 3..8, X=[A]
,
Теперь давайте попробуем это еще одним способом:
?- bagof(Q, (Q=A, ((1 #=< A, A #=< 5) ; (3 #=< A, A #=< 8))), X).
X = [A],
A in 3..5 ;
X = [A],
A in 3..5.
Арифметические ограничения объединяются, как и раньше, но у нас есть два ответа вместо одного.
Как все это можно объяснить?
РЕДАКТИРОВАТЬ: некоторые более странные результаты. Сравните это:
?- A=[_,_], bagof(Q, K1^K2^(Q=A, (A=[a,K1] ; A=[K2,b])), X).
A = [_G16886, b],
X = [[_G16886, b]] ;
A = [a, _G16889],
X = [[a, _G16889]].
с этим:
?- A=[a,b], bagof(Q, K1^K2^(Q=A, (A=[a,K1] ; A=[K2,b])), X).
A = [a, b],
X = [[a, b], [a, b]].
0 ответов
Это артефакт SWI-Prolog, который также копирует атрибутивные переменные при копировании findall/3. findall/3 копии используются внутри bagof/3 перед выполнением сортировки ключей /2. Но эффект уже можно объяснить с помощью findall/3:
SWI-Prolog, findall/3 копии приписанных переменных условий:
?- findall(A, A in 1..5, L).
L = [_3464],
_3464 in 1..5.
?- findall(A, (A in 1..5, (true; true)), L).
L = [_3762, _3768],
_3762 in 1..5,
_3768 in 1..5
Jekejeke Prolog, findall/3 не копирует условия атрибутивных переменных:
?- findall(A, A in 1..5, L).
L = [_A]
?- findall(A, (A in 1..5, (true; true)), L).
L = [_A, _B]
Внутри bagof/3 есть не только шаг сортировки ключей / 2, но и шаг восстановления переменных. На этом этапе для SWI-Prolog ограничения могут быть объединены, поскольку ограничения будут присутствовать.
Это объясняет первый результат в вопросе ОП. Второй результат в вопросе OP можно объяснить тем, что SWI-Prolog выполняет расширение цели и вводит новые переменные в случае (#=<) /2. Вы можете проверить себя:
?- [user].
test(A) :- A in 1..5 ; A in 3..8.
test(A) :- (1 #=< A, A #=< 5) ; (3 #=< A, A #=< 8).
?- listing(test/1).
test(A) :-
( ( integer(A)
-> between(1, 5, A)
; clpfd:clpfd_in(A, 1..5)
)
; integer(A)
-> between(3, 8, A)
; clpfd:clpfd_in(A, 3..8)
).
test(A) :-
( ( integer(A)
-> A>=1
; B=1,
clpfd:clpfd_geq(A, B)
),
( integer(A)
-> 5>=A
; C=5,
clpfd:clpfd_geq(C, A)
)
; ( integer(A)
-> A>=3
; D=3,
clpfd:clpfd_geq(A, D)
),
( integer(A)
-> 8>=A
; E=8,
clpfd:clpfd_geq(E, A)
)
).
В расширении (in)/2 нет свежих переменных. Но я предполагаю, что свежие переменные внутри расширения (#=<) / 2 заставят bagof/3 увидеть два решения вместо одного.
Изменить 19.08.2019:
Теперь мне интересно, как таблинг с помощью CLP(FD) решает проблему...