Анонимные переменные 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.