Чтобы дать вам представление о том, как использовать append/3
для извлечения элемента из списка списков, рассмотрим следующий предикат под названием replace/2
:
replace(In, Out) :-
append(LL, [L|RL], In),
append(LE, [E|RE], L),
replaceElement(E, NewE), !,
append(LE, [NewE|RE], NewL),
append(LL, [NewL|RL], Out).
replace(In, In).
Этот нерекурсивный предикат принимает, как положено In
, список списков и возвратных дорожек, чтобы найти элемент E
во внутреннем списке L
, который можно заменить с помощью replaceElement/2
; если это так, он заменяется сначала созданием внутреннего списка (NewL
), а затем использует этот новый список при построении нового внешнего списка (Out
), как результат.
Обратите внимание , что это просто служит для демонстрации того, как использовать append/3
для разбиения списка списков для извлечения отдельных элементов по мере необходимости с помощью обратного отслеживания, а не рекурсии, как требуется . Как только элемент E
заменяется на NewE
через replaceElement/3
, он снова используется при построении списка с использованием append/3
, как показано.
Также обратите внимание, что это предложение (которое предназначено для того, чтобы помочь вам, а не быть вашим окончательным ответом) также может заменить только один элемент во внутреннем списке, если он вообще есть. Если вы хотите выполнить несколько замен списка ввода за один вызов replace/2
или аналогичного , используя эту технику , то вам почти наверняка понадобится рекурсивное определение или возможность использовать глобальную базу данных с помощью assert
. Я рад, что меня поправят, если кто-то другой сможет дать определение в качестве контрпример.
В этом примере предикат replace/2
вместе со, скажем, следующим фактом:
replaceElement(6, 10).
Выполнение следующего дает нам требуемое поведение:
1 ?- replace([[1,1,1],[2,6,2],[3,3,3]], Out).
Out = [[1, 1, 1], [2, 10, 2], [3, 3, 3]] ;
false.
Если вы не можете использовать cut (!
), то его можно опустить, но учтите, что второе предложение replace(In, In)
приведет к тому, что все вызовы replace/2
будут отменены хотя бы один раз, чтобы вернуть вам список ввода. , Если такое поведение нежелательно, пропуск второго пункта приведет к тому, что replace/2
сразу выйдет из строя, если не будет произведена замена.