Неразрушающий универсальный количественный анализ в прологе - PullRequest
0 голосов
/ 03 марта 2019

Хороший язык для логического программирования должен позволять программисту использовать язык, близкий к языку, используемому математиками.Поэтому я всегда считал отсутствие надлежащего универсального квантификатора в Прологе важным недостатком.

Сегодня мне пришла идея, как определить что-то намного лучше, чем 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.

1 Ответ

0 голосов
/ 04 марта 2019

Отличная новость!Я был удивлен, что bagof написано на прологе.Глядя на его код, я узнал, что некоторые вещи, которые я считал невозможными, на самом деле возможны.И так же, как было предложено в руководстве SWI-Prolog, copy_term/3 или, точнее, похожий предикат copy_term_nat/2 помог.

Так что с большой радостью я могу представить полностью работающий (насколько я могу судить)универсальный квантификатор для SWI-Prolog:

forany(V, {Vars}, Condition, Body) :-
    findall(V-Vars, Condition, Solutions),
    % For SWI-Prolog.  Can be replaced by Solutions=Clean_solutions in other systems
    copy_term_nat(Solutions, Clean_solutions),
    forany_execute_goals(Clean_solutions, Vars, V, Body).

forany_execute_goals([], _, _, _).
forany_execute_goals([Sol-NewVars|Solutions], Vars, V, Body) :-
    % The following test can be removed
    assertion(subsumes_term(NewVars, Vars)),
    % or replaced by the following more standard use of throw/1:
%   (  subsumes_term(NewVars, Vars)
%   -> true
%   ;  throw('Forbidden instantiation of context variables by the antecedent of forany')  ),
    NewVars = Vars,
    call({Vars}/[V]>>Body, Sol),
    forany_execute_goals(Solutions, Vars, V, Body).
...