Рассмотрим эти модификации tol33t/2
:
tol33t([], []).
tol33t([Code|Codes], Remainder) :-
translate([Code], Translation), !,
tol33t(Codes, Rest),
append(Translation, Rest, Remainder).
tol33t([Code|Codes], [Code|Remainder]) :-
tol33t(Codes, Remainder).
Первый пункт - базовый вариант.
Второе предложение будет выполнено успешно, если будет текущий перевод Code
через translate/2
в виде списка символов произвольной длины (Translation
- обратите внимание, что вместо этого у вас было [Lower]
, что ограничивалорезультаты только для списков длины 1).Вырез (!
) после проверки на перевод кода приводит к рекурсивному нахождению Rest
решения, а затем добавляет Translation
вперед, как Remainder
для возврата.
Третье предложение выполняется, если во втором предложении не было перевода для текущего Code
(то есть вызова translate/2
).В этом случае отсутствие перевода для Code
означает, что мы просто возвращаем его как есть и вычисляем остальное.
РЕДАКТИРОВАТЬ:
Если вы не вырезали(!
), второе и третье предложения могут быть объединены в:
tol33t([Code|Codes], Remainder) :-
tol33t(Codes, Rest),
(translate([Code], Translation) ->
append(Translation, Rest, Remainder)
; Remainder = [Code|Rest]
).
Эта (неоптимизированная) версия проверяет на каждом Code
в списке символов , если есть translate/2
, который преуспевает;если это так, Translation
добавляется к Rest
, , иначе , Code
пропускается без изменений.Обратите внимание, что это имеет ту же семантику, что и реализация выше, в том смысле, что решения фиксируются (то есть имитируют срез !
), если прецедент к ->
(translate/2
) завершается успешно.Обратите внимание, что сокращение в обеих реализациях строго необходимо;без этого программа будет возвращаться к поиску решений, в которых привязки Code
не переводятся, если существует применимое предложение translate/2
.