Prolog рекурсивно заменяет элементы списка элементами другого списка

Извинения за отсутствие ясности в названии. Следующее - это очень специфический предикат, который я создаю, который работает частично только по назначению.

% replace_elements(+SearchingElementsList,+ReplacementsList,+OriginalList,-ResultingList).
% ResultingList consists of all elements of SearchingElementsList replaced by elements of ReplacementsList respectively.

replace_elements([],[],_,_).
replace_elements([H|T],[H2|T2],[H3|T3],List) :-
    H \= H3,                                 % H is not H3, therefore
    replace_elements([H|T],[H2|T2],T3,List). % Skip this element and continue with T3.
replace_elements([H|T],[H2|T2],[H|T3],[H2|List]) :-
    replace_elements(T,T2,T3,List).          % H is found in OriginalList. Continue with tails.

В настоящее время

?- replace_elements([1,2,3],[one,two,three],[1,2,3,4,5],Result).
?- Result = [one,two,three|_7636].

Ожидаемое:

?- Result = [one,two,three,4,5].

Любой намек будет оценен!

Изменить: Применил рабочий ответ для моей конкретной проблемы.

% Eventually, recursion starts from all empty lists.
replace_elements([],[],[],[]).
% Rules are empty, push remaining H to List.
replace_elements([],[],[H|T],[H|List]) :-
    replace_elements([],[],T,List).
% Empty list, just go through remaining rules.
replace_elements([H|T],[H2|T2],[],List) :-
    replace_elements(T,T2,[],List).
% H < H3, move to next element in rules.
replace_elements([H|T],[H2|T2],[H3|T3],List) :-
    H < H3,
    replace_elements(T,T2,[H3|T3],List).
% H > H3, move to next element in original list.
replace_elements([H|T],[H2|T2],[H3|T3],[H3|List]) :-
    H > H3,
    replace_elements([H|T],[H2|T2],T3,List).
% Element is the same, push replacement H2 to List.
replace_elements([H|T],[H2|T2],[H|T3],[H2|List]) :-
    replace_elements(T,T2,T3,List).

Ответ 1

Вот моя реализация, использующая if_/3 и расширенную версию memberd_t, добавляющую больше списка в качестве параметров, чтобы добиться как проверки списка поиска элементов, так и возвращения результата из R eplacementsList за один проход для эффективности:

replace_elements( [], [], _, _).
replace_elements([H|T], [H2|T1], Search_L, Replace_L):-
                if_( 
                      memberd_t(H, X, Search_L, Replace_L),
                      (
                         H2 = X,
                         replace_elements( T, T1,Search_L, Replace_L)
                      ),
                      (
                         H2 = H,
                         replace_elements( T, T1,Search_L, Replace_L)
                      )
                   ).  

memberd_t(H, X, Xs, Ys , T) :-
   i_memberd_t(Xs, Ys, H, X, T).   

i_memberd_t([], [], _, _, false).
i_memberd_t([X|Xs], [Y|Ys], E, H, T) :-
   if_( X = E, (T = true, H = Y) , i_memberd_t(Xs, Ys, E, H, T) ).

Некоторые тестовые файлы:

?- replace_elements([1,2,3,4,5],Result,[1,2,3],[one,two,three]).
Result = [one, two, three, 4, 5].


?- replace_elements([1,2,3,4,5],Result,[1,2,3],Ts).
Result = [_792, _894, _1032, 4, 5],
Ts = [_792, _894, _1032].



?- L = [1|L1], replace_elements(L ,[one,two,three,4,5],[1,2,3],[one,two,three]).
L = [1, 2, 3, 4, 5],
L1 = [2, 3, 4, 5] ;
L = [1, 2, three, 4, 5],
L1 = [2, three, 4, 5] ;
L = [1, two, 3, 4, 5],
L1 = [two, 3, 4, 5] ;
L = [1, two, three, 4, 5],
L1 = [two, three, 4, 5].


?- replace_elements(L ,[one,two,three,4,5],[1,2,3],[one,two,three]).
L = [1, 2, 3, 4, 5] ;
L = [1, 2, three, 4, 5] ;
L = [1, two, 3, 4, 5] ;
L = [1, two, three, 4, 5] ;
L = [one, 2, 3, 4, 5] ;
L = [one, 2, three, 4, 5] ;
L = [one, two, 3, 4, 5] ;
L = [one, two, three, 4, 5].
In_L = Result, Result = [] ;
In_L = [1],
Result = [one] ;
In_L = [1, 1],
Result = [one, one] ;
In_L = [1, 1, 1],
Result = [one, one, one] ;
In_L = [1, 1, 1, 1],
Result = [one, one, one, one] ;
In_L = [1, 1, 1, 1, 1],
Result = [one, one, one, one, one] ;
In_L = [1, 1, 1, 1, 1, 1],
Result = [one, one, one, one, one, one] ;
In_L = [1, 1, 1, 1, 1, 1, 1],
Result = [one, one, one, one, one, one, one] ;
In_L = [1, 1, 1, 1, 1, 1, 1, 1],
Result = [one, one, one, one, one, one, one, one] ;
In_L = [1, 1, 1, 1, 1, 1, 1, 1, 1],
Result = [one, one, one, one, one, one, one, one, one]...and goes on....


?- replace_elements([1,2,3,4,5],Result,[1,2,X],[one,two,three]).
Result = [one, two, three, 4, 5],
X = 3 ;
Result = [one, two, 3, three, 5],
X = 4 ;
Result = [one, two, 3, 4, three],
X = 5 ;
Result = [one, two, 3, 4, 5],
dif(X, 5),
dif(X, 4),
dif(X, 3).
Result = [one, two, three, 4, 5],
L = [1, 2, 3] ;
Result = [one, two, 3, three, 5],
L = [1, 2, 4] ;
Result = [one, two, 3, 4, three],
L = [1, 2, 5] ;
Result = [one, two, 3, 4, 5],
L = [1, 2, _22546],
dif(_22546, 5),
dif(_22546, 4),
dif(_22546, 3) ;
Result = [one, three, two, 4, 5],
L = [1, 3, 2] ;...and goes on...

until finally terminates (after a lot of answers) deterministicaly

Result = [1, 2, 3, 4, 5],
L = [_23992, _23998, _24004],
dif(_23992, 5),
dif(_23992, 4),
dif(_23992, 3),
dif(_23992, 2),
dif(_23992, 1),
dif(_23998, 5),
dif(_23998, 4),
dif(_23998, 3),
dif(_23998, 2),
dif(_23998, 1),
dif(_24004, 5),
dif(_24004, 4),
dif(_24004, 3),
dif(_24004, 2),
dif(_24004, 1).


?- L=[_,_,_],replace_elements([1,2,3,4,5],[one,two,three,4,5],L,T).
L = [1, 2, 3],
T = [one, two, three] ;
L = [1, 3, 2],
T = [one, three, two] ;
L = [2, 1, 3],
T = [two, one, three] ;
L = [3, 1, 2],
T = [three, one, two] ;
L = [2, 3, 1],
T = [two, three, one] ;
L = [3, 2, 1],
T = [three, two, one] ;
false.


?- replace_elements([1,2,3,4,5],[one,two,three,4,5],Fs,Ts).
Fs = [1, 2, 3],
Ts = [one, two, three] ;
Fs = [1, 2, 3, 4],
Ts = [one, two, three, 4] ;
Fs = [1, 2, 3, 4, 5|_9700],
Ts = [one, two, three, 4, 5|_9706] ;
Fs = [1, 2, 3, 4, _10176],
Ts = [one, two, three, 4, _10218],
dif(_10176, 5) ;
Fs = [1, 2, 3, 4, _10236, 5|_10244],
Ts = [one, two, three, 4, _10284, 5|_10292],
dif(_10236, 5) ;
Fs = [1, 2, 3, 4, _10384, _10390],
Ts = [one, two, three, 4, _10432, _10438],
dif(_10384, 5),
dif(_10390, 5) ;
Fs = [1, 2, 3, 4, ...and goes on...

Ответ 2

Я дам мыслительный процесс для решения проблемы. Пара принципов:

  • Мышление реляционно, а не императивно
  • Верхний дизайн

Вы хотите:

replace_elements(+SearchingElementsList, +ReplacementsList, +OriginalList, -ResultingList).

Я немного переименую его, чтобы он не был таким императивным:

translated_list(Trans1, Trans2, List1, List2).

Я удалил + и -, потому что в идеале мы хотели бы, чтобы это было как можно более общее отношение. Это отношение состоит в том, что соответствующие элементы в List1 и List2 связаны друг с другом через "таблицу перевода", определяемую соответствующими элементами в Trans1 и Trans2.

В Prolog при рассмотрении соответствующих элементов списка я сразу же думаю о том, чтобы использовать что-то вроде maplist. Кроме того, неудобно обрабатывать два независимых списка для определения отношения 1-1 между терминами. Легче и чище использовать единую таблицу переводов с элементами, которые выглядят, например, t1-t2.

translated_list(Trans1, Trans2, List1, List2) :-
    % TransTable is a translation table consisting of t1-t2 pairs from Trans1 and Trans2
    maplist(trans_table_element, Trans1, Trans2, TransTable),

    % List1 and List2 are related using the translation table, TransTable
    maplist(corresponding_element(TransTable), List1, List2).

Теперь нам нужен предикат trans_table, который обеспечивает связь между элементами таблицы перевода. Это соотношение говорит, что элемент в таблице переводов E1-E2, где соответствующие отдельные элементы E1 и E2:

trans_table_element(E1, E2, E1-E2).

И нам нужен предикат, который описывает два соответствующих элемента, используя таблицу переводов.

corresponding_element(TransTable, E1, E2) :-
(    member(E1-E2, TransTable)
->   true            % Translation exists
;    E1 = E2         % Translation doesn't exist
).

Из этого вы получите:

| ?- translated_list([1,2,3], [one, two, three], [4,1,3,5,2,1,3], L).

L = [4,one,three,5,two,one,three]

yes
| ?-

Также как:

| ?- translated_list([1,2,3], [one, two, three], L, [4,one,three,5,two,one,three]).

L = [4,1,3,5,2,1,3] ? a

no

и

| ?- translated_list(A, B, [4,1,3,5,2,1,3], [4,one,three,5,two,one,three]).

A = [4,1,3,5,2]
B = [4,one,three,5,two] ? ;

A = [4,1,3,5,2,_]
B = [4,one,three,5,two,_] ? ;

...

Если вы хотите применить в своих правилах, что таблица переводов переводит только разные элементы, вы можете определить:

trans_table_element(E1, E2, E1-E2) :- dif(E1, E2).

И тогда вы получите (используя SWI Prolog на этот раз):

2 ?-  translated_list(A, B, [4,1,3,5,2,1,3], [4,one,three,5,two,one,three]).
A = [1, 3, 2],
B = [one, three, two] ;
A = [1, 3, 2, _1240],
B = [one, three, two, _1276],
dif(_1240, _1276) ;
A = [1, 3, 2, _1492, _1498],
B = [one, three, two, _1534, _1540],
dif(_1492, _1534),
dif(_1498, _1540) ;
...


UPDATE

Возможное улучшение вышеприведенной реализации, чтобы сделать ее более реляционной, избегая конструкцию ->/;, мы можем определить не членство реляционно, используя maplist.

corresponding_element(TransTable, E1, E2) :-
    member(E1-E2, TransTable).
corresponding_element(TransTable, E1, E2) :-
    maplist(dif(E1-E2), TransTable),
    E1 = E2.

В дополнение к приведенным выше результатам, получаем:

6 ?- translated_list([1,2,3],Ts,[1,2,3,4,5],R).
Ts = [_9016, _9034, _9052],
R = [_9016, _9034, _9052, 4, 5] ;
Ts = [_9640, _9646, _9652],
R = [_9640, _9646, 3, 4, 5],
dif(3, _9652) ;
Ts = [_9640, _9646, _9652],
R = [_9640, 2, _9652, 4, 5],
dif(2, _9646) ;
Ts = [_9856, _9862, _9868],
R = [_9856, 2, 3, 4, 5],
dif(2, _9862),
dif(3, _9868)
...

Ответ 3

Это отношение можно выразить довольно компактно с помощью if_/3, =/3 и maplist/3

:- use_module(library(apply)).   % for maplist/3

from_to_elem_repl([],[],E,E).
from_to_elem_repl([X|Xs],[Y|Ys],E,R) :-
   if_(E=X,R=Y,from_to_elem_repl(Xs,Ys,E,R)).

from_to_list_mapped(Fs,Ts,L,M) :-
   maplist(from_to_elem_repl(Fs,Ts),L,M).

Предикат from_to_elem_repl/4 описывает связь между элементом и его заменой. Если элемент E встречается в списке, то он заменяется элементом в соответствующей позиции в списке: Y (рекурсивное правило). Если E не встречается в списке, он не заменяется (базовый регистр). Предикат from_to_list_mapped/4 использует maplist/3 для отображения предиката from_to_elem_repl/4 в список L, что дает список с заменой M. Ваш пример запроса успешно детерминирован:

?- from_to_list_mapped([1,2,3],[one,two,three],[1,2,3,4,5],M).
M = [one, two, three, 4, 5].

В другом направлении найдено все восемь решений:

?- from_to_list_mapped([1,2,3],[one,two,three],L [one,two,three,4,5]).
L = [1, 2, 3, 4, 5] ;
L = [1, 2, three, 4, 5] ;
L = [1, two, 3, 4, 5] ;
L = [1, two, three, 4, 5] ;
L = [one, 2, 3, 4, 5] ;
L = [one, 2, three, 4, 5] ;
L = [one, two, 3, 4, 5] ;
L = [one, two, three, 4, 5].

Вы также можете запросить возможные пары отображения для данного списка и его замены:

?- from_to_list_mapped(Fs,Ts,[1,2,3,4,5],[one,two,three,4,5]).
Fs = [1, 2, 3],
Ts = [one, two, three] ;
Fs = [1, 2, 3, 4],
Ts = [one, two, three, 4] ;
Fs = [1, 2, 3, 4, 5|_G5111],
Ts = [one, two, three, 4, 5|_G5114] ;
Fs = [1, 2, 3, 4, _G5258],
Ts = [one, two, three, 4, _G5279],
dif(_G5258, 5) ;
Fs = [1, 2, 3, 4, _G5275, 5|_G5279],
Ts = [one, two, three, 4, _G5299, 5|_G5303],
dif(_G5275, 5) ;
Fs = [1, 2, 3, 4, _G5316, _G5319],
Ts = [one, two, three, 4, _G5340, _G5343],
dif(_G5316, 5),
dif(_G5319, 5) ;
Fs = [1, 2, 3, 4, _G5333, _G5336, 5|_G5340],
Ts = [one, two, three, 4, _G5360, _G5363, 5|_G5367],
dif(_G5333, 5),
dif(_G5336, 5) ;
.
.
.

Очевидно, существует бесконечно много возможностей. Но если вы запрашиваете фиксированную длину, предикат заканчивается:

?- Fs=[_,_,_],from_to_list_mapped(Fs,Ts,[1,2,3,4,5],[one,two,three,4,5]).
Fs = [1, 2, 3],
Ts = [one, two, three] ;
Fs = [1, 3, 2],
Ts = [one, three, two] ;
Fs = [2, 1, 3],
Ts = [two, one, three] ;
Fs = [3, 1, 2],
Ts = [three, one, two] ;
Fs = [2, 3, 1],
Ts = [two, three, one] ;
Fs = [3, 2, 1],
Ts = [three, two, one] ;
false.

Вы также можете запросить сопоставление без указания элементов замены:

?- from_to_list_mapped([1,2,3],Ts,[1,2,3,4,5],R).
Ts = [_G4920, _G4937, _G4965],
R = [_G4920, _G4937, _G4965, 4, 5].

Как вы видите, предикат довольно универсален. Играйте с ним, чтобы найти другие возможные варианты использования.