Мне нужно перебрать диапазон чисел (например, используя between/3
) от 1 до Length
, где Length
- длина заданного списка.Повторное число, скажем, N
, затем применяется к предикату, скажем, do_something
, пока оно не перестанет работать.То есть do_something
ищет правильный N
, после чего все точки выбора between/3
должны быть отброшены.Однако все точки выбора do_something
с соответствующим N
должны быть выполнены.
Попытка кулака была примерно такой:
% main(+InputList, -N, -OutputList)
main(InputList, N, OutputList) :-
length(InputList, Length),
between(1, Length, N),
% cut all between/3 choice points as soon as Num is instantiated
freeze(Num, !),
do_something(InputList, N, OutputList),
Num is N.
Это не сработало, поскольку freeze/2
неbetween/3
выбор очков.Версия с when/2
тоже не работала.Я понимаю, это потому, что оба freeze/2
и when/2
выполняются в отдельном потоке и не влияют на основной поток, где between/3
.
Через некоторое время я получил следующий код, которыйделает то, что нужно, но неэффективно:
main(InputList, N, OutputList) :-
length (InputList, Length),
between(1, Length, N),
do_something(InputList, N, _),
% cut all prior choice points as soon as proper N is found
!,
% start do_something over!
do_something(InputList, N, OutputList).
Неэффективность в том, что точка выбора do_something
с правильным N
выполняется дважды.Сначала непосредственно перед резкой, а затем еще раз сразу после нее.
Хотя это решение работает в моем случае, оно не применимо к универсальному случаю, когда все do_something
точки выбора должны выполняться только один раз.
Обратите внимание, что N
должен быть минимальным из диапазона 1..Length
и заранее не известен.Следовательно, ищите его с помощью do_something
.
Есть ли лучшее решение для этого?Есть ли способ реализовать предикат, похожий на between/3
, который может прекратиться при сигнале?Может ли быть специализированный встроенный предикат, который делает то, что нужно?Любые плодотворные идеи высоко ценятся.