#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]),!.