Анонимные переменные Prolog nth1

у меня есть список с целыми числами и анонимными переменными, и я пытаюсь найти индекс специальных значений. Проблема в том, как только я использую nth1/3 чтобы найти индексы, Prolog присваивает значения анонимным переменным, и поэтому я тоже нахожу индексы.

пример: List = [1,_,1], где я хочу, в результате X = 1, X = 3 С nth1(X,List,1), но, как указано, прежде чем я получу X = 1, X = 2, X = 3.

3 ответов


есть несколько проблемная проблема, скрытая в ваших требованиях: они нарушение важное декларативное свойство под названием монотонности. Под этим мы подразумеваем, что добавлять ограничения могут в лучшем случае сделать решение более конкретную, не более общие.

например, с решением, которое вы разместили, мы получаем:

?- list_el_index([_], 1, N).
false.

Теперь добавить ограничение путем наложения дополнительного требование к доселе свободной анонимной переменной:

?- Var = 1, list_el_index([Var], 1, N).
Var = 1,
N = 0 .

Я имею в виду:пришел на! Мы добавили ограничения и как следствие больше решений, чем раньше? Такой результат неудачен и мешает нам рассуждать в логическое кстати об этой программе.

программа также подводит нас в других отношениях. Например, спросим:какие решения существуют на всех?

?- list_el_index(Ls, El, I).
nontermination

в идеале, мы хотели бы, чтобы программа создать решений в таких случаях! Эта общность является одной из главных достопримечательностей логического программирования и отличает ее от более низкоуровневых парадигм.


один из способов решения таких проблем является символически выделить разные видов элементов, которые появляются в вашем списке.

например, давайте использовать:

  • u на неизвестный значение.
  • i(I) на целое I.

С этим новым представлением, ваше решение будет:

list_el_index([i(I)|_], I, 0).
list_el_index([_|Tail], Element, Index) :-
    list_el_index(Tail, Element, Index0),
    Index #= Index0+1.

Я также взял на себя смелость заменить (is)/2 by (#=)/2, рекламировать и придерживаться более общей целочисленной арифметики, которая позволяет нам более свободно переупорядочивать цели, если это необходимо. В зависимости от вашей реализации Prolog вы можете необходимо импортировать библиотеку, чтобы извлечь выгоду из (#=)/2.

С этим представлением ваш начальный случай становится:

?- list_el_index([i(1),u,i(1)], 1, Index).
Index = 0 ;
Index = 2 ;
false.

это работает по желанию!

важно отметить, что мы также можем использовать предикат в целом, а именно создать варианты ответов:

?- list_el_index(Ls, El, I).
Ls = [i(El)|_2994],
I = 0 ;
Ls = [_2992, i(El)|_3000],
I = 1 ;
Ls = [_2992, _2998, i(El)|_3006],
I = 2 ;
Ls = [_2992, _2998, _3004, i(El)|_3012],
I = 3 .

из-за программы монотонности, можно довольно перечислить решения по итеративным углублением:

?- length(Ls, _), list_el_index(Ls, El, I).
Ls = [i(El)],
I = 0 ;
Ls = [i(El), _4812],
I = 0 ;
Ls = [_4806, i(El)],
I = 1 ;
Ls = [i(El), _4812, _4818],
I = 0 ;
etc.

это стало возможным благодаря использованию представления, которое позволяет нам различать случаи по шаблоны. Рассмотрите возможность использования этого подхода для использования ваших программ во всех направлениях и для применения логических рассуждений. Он довольно прост в применении, используя соответствующую оболочку или константу, и значительно увеличивает общность ваших программ.


это работает :

 - L = [1,_,1], nth1(X, L, Y), ground(Y), Y= 1.
L = [1,_310914,1],
X = Y, Y = 1 ;
L = [1,_310914,1],
X = 3,
Y = 1.

благодаря подсказке lurkers, я придумал это решение.

list_el_index([El1|_], El2, 0) :-
    El1 == El2.
list_el_index([_|Tail], Element, Index) :-
    list_el_index(Tail, Element, Index1),
    Index is Index1+1.