Сопрограмма в Прологе: когда аргумент является списком (он имеет фиксированную длину)

Вопрос

Можно ли запланировать выполнение цели, как только длина списка будет известна / исправлена, или, как указывает @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.
Другие вопросы по тегам