Пролог: элемент, отсутствующий в списке

#list #search #prolog

#Список #Поиск #пролог

Вопрос:

Мне нужно найти позицию элемента в списке (как встроенный предикат nth, но здесь первый элемент имеет индекс 1). Но мне также нужен вывод типа «Элемент отсутствует», если нет. Я пробую решение, не столь элегантное, присваивая счетчику большое значение.
Но это неправильное решение!!!
Боюсь, это очень просто, но я не могу найти другого решения!!!

Кто-нибудь может мне помочь?

 search(L):-
      write('searching for: '),read(E),find(L,E,Pos),
      out(L,E,Pos),!.

out(E,Pos):-
          Pos < 10000,
          write('element '),write(E),write(' is in position n. '),write(Pos),!.

out(E,Pos):-
          Pos > 10000,
          write('Element '),write(E),write(' is not present!'),!.

find([X|Xs],E,Pos):-
                 X = E,
                 find(Xs,E,Pos1),
                 Pos is Pos1   1.
find([],_,10000).
find([X],X,1).
find([X|_],X,Pos):-
                Pos is 1,!.
  

Комментарии:

1. Как насчет использования значения 0 для обозначения отсутствующего элемента? Ваш первый элемент имеет индекс 1, так что это, казалось бы, безопасный вариант.

2. Потому что в хвостовой рекурсии prolog выполняет строку «Pos равно Pos1 1». в каждом случае.

3. Я не предлагаю использовать 0 в конечной рекурсии, только в качестве возвращаемого значения, которое, как я думал, вы искали вместо «большого значения». Смотрите ответ Raceimaztion о том, как что -либо может быть возвращено в случае отсутствия элемента. Код этого ответа не является хвостовым рекурсивным, но это можно исправить с помощью вспомогательного предиката. Однако, если вы удовлетворены ответом z5h «Просто дайте ему завершиться неудачей», это, безусловно, элегантно.

Ответ №1:

То, что вы хотите, больше похоже на это:

 search(L):-
    write('searching for: '),read(E),
    finde(E).

finde(E) :-
    find(L,E,Pos), % find succeeds 
    out(L,E,Pos),!. % and prints, cut ensures we don't try next clause

finde(E) :- write('Element '),write(E),write(' is not present!'),!. % called if not found
  

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

Комментарии:

1. Я думаю, что ваш ответ очень эффективен! Спасибо!

Ответ №2:

Помните, что вы не ограничены возвращением чисел из вашего предиката find / 3.

Вместо этого вы можете вернуть любой другой атом, например:

 find([], _, notfound).
find([H|_], H, 1) :- !
find([_|T], H, Pos) :-
        find(T, H, Found),
        (
            integer(Found), !,
            Pos is Found 1
        );(
            Pos = notfound
        ).
  

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

Отредактировано для исправления ошибки.

Комментарии:

1. Вы также можете включить хвостовую рекурсию, например, используя find / 4 , который может привести к сбою, и find / 3 , который возвращает описательное или нулевое значение в случае сбоя для отсутствующих элементов.

2. Я не понимаю… в моем swi-prolog у меня такой результат: 15?- find ([2,3,4], 2, Pos). Pos = 1. 16 ?- найти([2,3,4],3,Pos). ОШИБКА: is/2: аргументы недостаточно созданы 17 ?- find([2,3,4],4,Pos). ОШИБКА: is/2: аргументы недостаточно созданы 18 ?- find([2,3,4],5,Pos).<br/> Pos = notfound.<br/></p>

3. @hardmath, @Aleg, Бах, вот что я получаю за то, что пишу это без тестирования. Сейчас я это исправил, хотя теперь вижу, что это не лучшее решение.

Ответ №3:

 

search(L):-
        write('searching for: '),
        read(E),
        find(L,E,Pos),
        fail.
search(_).

find(L,E,0) :-
         (append(_,[E|_],L)),!.
find(L,E,Pos) :-
        append(L0,[E|_],L),
        length(L0,Len0),
        Pos is Len   1.
find(_,_,-1).

out(E,0) :-
        writef('element %t is not present. ',[E]),!.
out(E,-1) :-
        writef('element %t is no longer present. ',[E]),!.
out(E,Pos) :-
        writef('element %t is in position %t. ',[E,Pos]),!.

  

Комментарии:

1. Похоже, что во втором правиле / предложении для find / 3 допущена опечатка. Переменная Len не была привязана при вычислении Pos, поэтому, предположительно, вы имели в виду Len0 здесь (привязанный в предыдущей подцели).

Ответ №4:

 
% NewLine was missing.

out(E,0) :-
        writef('element %t is not present. n',[E]),!.
out(E,-1) :-
        writef('element %t is no longer present. n',[E]),!.
out(E,Pos) :-
        writef('element %t is in position %t. n',[E,Pos]),!.