Я бы выбрал следующий подход. Ключевые элементы этого решения:
Использование nth1/3
для рассмотрения элемента списка в указанной позиции
=../2
для отображения между термином с аргументами и списком
Предикат «подстановки», который заменяет значение в указанной позиции в списке другим
subst([_|T], Y, 1, [Y|T]).
subst([X|T], Y, N, [X|T1]) :-
N #> 1,
N1 #= N - 1,
subst(T, Y, N1, T1).
executed(AS, swap(X,Y), NS) :-
AS =.. [regs|P],
nth1(X, P, Xe),
nth1(Y, P, Ye),
subst(P, Ye, X, P1),
subst(P1, Xe, Y, P2),
NS =.. [regs|P2].
executed(AS, move(X), NS) :-
AS =.. [regs|P],
nth1(X, P, Xe),
X1 #= X + 1,
subst(P, Xe, X1, P1),
NS =.. [regs|P1].
Если вы используете пролог SWI, вам необходимо включить библиотеку clpfd, :- use_module(library(clpfd)).
. Также некоторые прологи, такие как Ciao Prolog, не имеют nth1/3
. Однако Ciao предоставляет nth/3
с таким же поведением, поэтому его можно заменить.
Обратите внимание, что здесь я использую CLP (FD) для большей общности. Если ваша система не поддерживает CLP (FD), вы можете использовать is
вместо #=
, хотя это менее желательно.
Обратите внимание, что это решение работает до тех пор, пока аргументы, индексирующие регистры, " в диапазоне". Так что это не сработает на executed(regs(1,2,+), move(3), NS).
. В качестве упражнения, если это необходимо, вы должны попытаться улучшить это решение для удовлетворения этой потребности. Это поможет вам изучить Prolog, а не получить каждую деталь решения.