Сопрограмма в Прологе: когда аргумент является списком (он имеет фиксированную длину)
Вопрос
Можно ли запланировать выполнение цели, как только длина списка будет известна / исправлена, или, как указывает @false в комментариях, данный аргумент становится [правильным] списком? Что-то вроде этого:
when(fixed_length(L), ... some goal ...).
Когда-условия могут быть построены с использованием ?=/2
, nonvar/1
, ground/1
, ,/2
, а также ;/2
только и кажется, что они не очень полезны при просмотре всего списка.
В качестве дальнейшей детали я ищу решение, которое представляет логическую чистоту, если это возможно.
мотивация
Я думаю, что это условие может быть полезно, когда кто-то хочет использовать предикат p(L)
проверить свойство для списка L
, но без использования его в генеративной форме.
Например, это может быть тот случай, когда [по причинам эффективности или прекращения] предпочитают выполнить следующее соединение p1(L), p2(L)
в этом порядке, если L
имеет фиксированную длину (т.е. L
список), и в обратном порядке p2(L), p1(L)
в противном случае (если L
это частичный список).
Это может быть достигнуто следующим образом:
when(fixed_length(L), p1(L)), p2(L).
Обновить
Я реализовал решение, но ему не хватает чистоты.
2 ответа
Было бы хорошо, если when/2
будет поддерживать условие list/1
, А пока рассмотрим:
list_ltruth(L, Bool) :-
freeze(L, nvlist_ltruth(L, Bool)).
nvlist_ltruth(Xs0, Bool) :-
( Xs0 == [] -> Bool = true
; Xs0 = [_|Xs1] -> freeze(Xs1, nvist_ltruth(Xs1, Bool))
; Bool = false
).
when_list(L, Goal_0) :-
nvlist_ltruth(L, Bool),
when(nonvar(Bool),( Bool == true, Goal_0 )).
Таким образом, вы можете комбинировать это и с другими условиями.
Может выдать ошибку типа, если L
это не список
when(nonvar(Bool), ( Bool == true -> Goal_0 ; sort([], L) ).
Вышеупомянутый трюк будет работать только в системе Prolog, соответствующей ISO, такой как SICStus или GNU, которая производит type_error(list,[a|nonlist])
за sort([],[a|nonlist])
в противном случае замените его на:
when(nonvar(Bool),
( Bool == true -> Goal_0 ; throw(error(type_error(list,L), _)).
Многие системы содержат некоторые специфические для реализации встроенные подобные '$skip_list'
для быстрого просмотра списков, вы можете использовать его здесь.
Мне удалось ответить на мой собственный вопрос, но не с чистым решением.
Некоторые наблюдения
Трудность, с которой сталкиваются при написании программы, которая планирует какую-то цель для выполнения, когда длина списка точно известна, заключается в том, что фактическое условие может измениться. Учти это:
when(fixed_length(L), Goal)
Длина списка может измениться, если L
является несвязанным или если последний хвост не связан. Скажем, у нас есть этот аргумент L = [_,_|Tail]
, L
имеет фиксированную ширину, только если Tail
имеет фиксированную ширину (другими словами, L
это список, если T
это список). Итак, условие, которое проверяет Tail
может быть, единственное, что нужно сделать сначала. Но если Tail
становится [a|Tail2]
новое условие когда проверяет, Tail2
список необходим.
Решение
1. Получение условия когда
Я реализовал предикат, который связывает частичный список с условием when, которое сигнализирует, когда он может стать списком (т.е. nonvar(T)
где T
самый глубокий хвост).
condition_fixed_length(List, Cond):-
\+ (List = []),
\+ \+ (List = [_|_]),
List = [_|Tail],
condition_fixed_length(Tail, Cond).
condition_fixed_length(List, Cond):-
\+ \+ (List = []),
\+ \+ (List = [_|_]),
Cond = nonvar(List).
2. Рекурсивно, когда кондиционирование
check_on_fixed_length(List, Goal):-
(
condition_fixed_length(List, Condition)
->
when(Condition, check_on_fixed_length(List, Goal))
;
call(Goal)
).
Примеры запросов
Предположим, мы хотим проверить, что все элементы L
являются a
когда размер L
фиксированный:
?- check_on_fixed_length(L, maplist(=(a), L)).
when(nonvar(L), check_on_fixed_length(L, maplist(=(a), L))).
... а потом L = [_,_|Tail]
:
?- check_on_fixed_length(L, maplist(=(a), L)), L = [_,_|L1].
L = [_G2887, _G2890|L1],
when(nonvar(L1), check_on_fixed_length([_G2887, _G2890|L1], maplist(=(a), [_G2887, _G2890|L1]))).
?- check_on_fixed_length(L, maplist(=(a), L)), L = [_,_|L1], length(L1, 3).
L = [a, a, a, a, a],
L1 = [a, a, a].
нечистота
conditon_fixed_length/2
является источником примесей, как это видно из следующего запроса:
?- L = [X, Y|Tail], condition_fixed_length(L, Cond), L = [a,a].
L = [a, a],
X = Y, Y = a,
Tail = [],
Cond = nonvar([]).
?- L = [X, Y|Tail], L = [a, a], condition_fixed_length(L, Cond).
false.