Альтернатива для поиска

Я пытаюсь создать альтернативу findall в прологе.

Что у меня есть:

solutions(A,T,S) :- 
   T,
   assert(temp(A)),
   fail.
solutions(A,T,S) :-
   obtain([],S).

obtain(X,S) :-
   retract(temp(A)),
   obtain([A|X],S).
obtain(S,S).

Это, однако, дает мне противоречивые результаты. Что случилось? Заранее спасибо.

1 ответ

Есть несколько проблем с вашей реализацией.

  1. Там нет очистки в начале. добавлять retractall(temp(_)) до T,

  2. obtain/2 удастся получить много разных ответов, потому что retract(temp(A)) даст много ответов, и потому что второй пункт obtain(S,S) всегда будет решением. Это можно сохранить, добавив разрез после retract,

     |?- получить ([],S).
    S = [2,1]?;
    S = [1]?;
    S = [2]?;
    S = []?;
    нет
    

  3. Вы можете изменить порядок, либо с помощью asserta/1 или путем переопределения obtain/2,

  4. Ваше определение не является повторным. Это не может быть решено легко. Вам понадобится либо немного gensym как функциональность или некоторые даже более продвинутые функции.

  5. Для мелкого шрифта assert/1 против assertz/1 увидеть этот ответ.

Попробуйте это, сделав вырез (!) После retract / 1 и явно assertz/1:

solutions(A,T,_) :- 
   T,
   assertz(temp(A)),
   fail.
solutions(_,_,S) :-
   obtain(S).

obtain([A|S]) :-
   retract(temp(A)), !,
   obtain(S).
obtain([]).

Работает нормально, но не повторяется, второй результат запроса неверен:

?- solutions(X,between(1,3,X),L).
L = [1, 2, 3].

?- solutions(X-R,(between(1,3,X),solutions(Y,between(1,X,Y),R)),L).
L = [3-[2-[1-[1], 1, 2], 1, 2, 3]].

Изменить 08.11.2020:
вот реентерабельное решение с использованием gensym/2:

solutions(A,T,L) :-
   setup_call_cleanup(
      gensym('bag',B),
      solutions(B,A,T,L),
      retractall(temp(B,_))).

solutions(B,A,T,_) :- 
   T,
   assertz(temp(B,A)),
   fail.
solutions(B,_,_,S) :-
   obtain(B,S).

obtain(B,[A|S]) :-
   retract(temp(B,A)), !,
   obtain(B,S).
obtain(_,[]).

Теперь оба запроса работают нормально:

?- solutions(X,between(1,3,X),L).
L = [1, 2, 3].

?- solutions(X-R,(between(1,3,X),solutions(Y,between(1,X,Y),R)),L).
L = [1-[1], 2-[1, 2], 3-[1, 2, 3]].

Предупреждение: система Prolog с семантикой логического обновления
может быть неэффективной во время многократного отзыва /1.

Другие вопросы по тегам