Хороший язык для логического программирования должен позволять программисту использовать язык, близкий к языку, используемому математиками.Поэтому я всегда считал отсутствие надлежащего универсального квантификатора в Прологе важным недостатком.
Сегодня мне пришла идея, как определить что-то намного лучше, чем forall
и foreach
.
* 1006.*
forany(Var, {Context}, Condition, Body)
Этот предикат пытается доказать Body
для всех экземпляров Var
последовательно возвращается при возврате через Condition
.Все переменные в Condition
и Body
считаются локальными, если они не указаны в Var
или Context
.Condition
не разрешается каким-либо образом изменять переменные, перечисленные в Context
, в противном случае forany
не будет работать правильно.
Вот реализация (основанная на yall):
forany(V, {Vars}, Goal1, Goal2) :-
( bagof(V, {V,Vars}/Goal1, Solutions)
-> maplist({Vars}/[V]>>Goal2, Solutions)
; true ).
Мой первый вопрос касается второго аргумента forany
.Я хотел бы устранить это.
Теперь несколько примеров
Составьте список из первых 8 квадратов:
?- length(X,8), forany(N, {X}, between(1,8,N),
(Q is N*N, nth1(N, X, Q))).
X = [1, 4, 9, 16, 25, 36, 49, 64].
Обратный список:
?- X=[1,2,3,4,5], length(X,N), length(Y,N),
forany(I, {X,Y,N}, between(1,N,I),
(J is N-I+1, nth1(I,X,A), nth1(J,Y,A))).
X = [1, 2, 3, 4, 5],
N = 5,
Y = [5, 4, 3, 2, 1].
Подмножество:
subset(X, Y) :- forany(A, {X,Y}, member(A,X), member(A, Y)).
Забавный способ генерации всех перестановок списка без дубликатов:
permutation(X, Y) :-
length(X, N), length(Y, N), subset(X, Y).
?- permutation([1,2,3],X).
X = [1, 2, 3] ;
X = [1, 3, 2] ;
X = [2, 1, 3] ;
X = [2, 3, 1] ;
X = [3, 1, 2] ;
X = [3, 2, 1] ;
false.
Забавный способ сортировки списка различных целых чисел.Обратите внимание, что для сортировки списка используются ограничения, поэтому большинство перестановок не будет сгенерировано:
sorted(X) :- forany(A-B, {X}, append(_, [A,B|_], X),
A#<B).
?- X=[7,3,8,2,6,4,9,5,1], length(X, N), length(Y, N),
sorted(Y), subset(X,Y).
X = [7, 3, 8, 2, 6, 4, 9, 5, 1],
N = 9,
Y = [1, 2, 3, 4, 5, 6, 7, 8, 9] .
Проблема
Кажется, что этот forany
прекрасно работает, когда ограничения не используются,Кроме того, его можно использовать для создания ограничений, но, по крайней мере, в SWI-Prolog существуют проблемы, когда ограничения уже созданы.Причина этого заключается в том, что forany
использует bagof
и в соответствии с руководством SWI-Prolog:
Операции копирования терминов (assertz/1
, retract/1
, findall/3
, copy_term/2
и т. Д.) Также обычно копируют ограничения.Эффект варьируется от нормального, тихого копирования огромных сетей ограничений до нарушений внутренней согласованности сетей ограничений.Как правило, копирование терминов, содержащих атрибуты, не рекомендуется.Если вам нужно рассуждать о термине, который связан с ограничениями, используйте copy_term/3
, чтобы получить ограничения как цели Prolog, и используйте эти цели для дальнейшей обработки.
Вот демонстрация проблемыbagof
создает с ограничениями:
?- X=[A,B,C], dif(C,D), bagof(_, K^member(K,X), _).
X = [A, B, C],
dif(C, _5306),
dif(C, _5318),
dif(C, _5330),
dif(C, D).
Как видите, создаются три ненужных ограничения.
Мой второй вопрос: если это проблема только SWI-Prolog.
И третий вопрос: есть ли способ исправить это в SWI-Prolog.Приведенная выше цитата из руководства предполагает использование copy_term/3
.К сожалению, я не понимаю это предложение и не знаю, полезно ли оно для forany
.