2009-11-23 2 views
1

Я пытаюсь сделать функцию пролога. Функция читает в предложении, а затем пытается извлечь ключевое слово. Если ключевое слово найдено, оно печатает сообщение. Я хочу, чтобы он также распечатывал сообщение, если ключевые слова не найдены. Вот мой пример:SWI Prolog - условный NOT?

contains([word1|_]) :- write('word1 contained'). 
contains([Head|Tail]) :- Head \= word1, contains(Tail). 
contains([word2|_]) :- write('word2 contained'). 
contains([Head|Tail]) :- Head \= word2, contains(Tail). 
contains([word3|_]) :- write('word3 contained'). 
contains([Head|Tail]) :- Head \= word3, contains(Tail). 

Приведенный выше код проверяет и показывает, присутствует ли извлеченное слово. Но он не дает ответа, если слова «word1, word2 или word3» не содержатся. Кто-нибудь знает, как я должен это реализовать?

Я попытался добавить:

contains([_|_]) :- write('nothing contained'),nl. 
contains([Head|Tail]) :- Head \= _, contains(Tail). 

Но ясно, что это неправильно, что нужно делать.

ответ

4

стандартный способ написать основную часть вашего содержит предикат:

contains([word1|_]) :- !, write('word1 contained'). 
contains([word2|_]) :- !, write('word2 contained'). 
contains([word3|_]) :- !, write('word3 contained'). 
contains([Head|Tail]) :- contains(Tail). 

Что означает:

  • когда вы найдете слово, не искать дальше (это то, что разрез() оператор для сравнения!).
  • Когда ничего не работало, рекурсия на хвосте.

Чтобы добавить ответ в случае, если ничего не найдено, просто добавьте еще один разрез на рекурсивный вызов, так что позже дело только вызывается, когда ничего другого (в том числе и рекурсии) работали:

contains([word1|_]) :- !, write('word1 contained'). 
contains([word2|_]) :- !, write('word2 contained'). 
contains([word3|_]) :- !, write('word3 contained'). 
contains([Head|Tail]) :- contains(Tail), !. 
contains(_) :- write('Nothing found'). 
+0

Использование разрезов не считается приятным. – liori

+1

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

+1

Плюс, использование 'write' означает, что программа все равно не является логической. – bcat

2

На императивном языке вы использовали бы какой-то флаг; например:

found = False 
for word in wordlist: 
    if word in ('car', 'train', 'plane'): 
     print "Found: " + word 
     found = True 
if not found: 
    print "Nothing found." 

Вы можете реализовать этот флаг в качестве другого параметра для ваших статей:

% entry point 
contains(X) :- contains(X, false). 

% for each word... 
contains([Word|Rest], Flag) :- 
    Word = car -> (write('Car found.'), nl, contains(Rest, true)) ; 
    Word = train -> (write('Train found.'), nl, contains(Rest, true)) ; 
    Word = plane -> (write('Plane found.'), nl, contains(Rest, true)) ; 
    contains(Rest, Flag). 

% end of recursion 
contains([], true). 
contains([], false) :- write('Nothing found.'), nl. 

Если вы хотите сделать четкое положение для каждого слова (и абстрактного цикла), изменение средней части чтобы:

% for each word... 
contains([Word|Rest], Flag) :- 
    checkword(Word) -> NewFlag=true ; NewFlag=Flag, 
    contains(Rest, NewFlag). 

% and at the end: 
checkword(car) :- write('Car found.'), nl. 
checkword(plane) :- write('Plane found.'), nl. 
checkword(train) :- write('Train found.'), nl. 
+0

Единственная проблема с этим решением является то, что, потому что моя функция вызывается несколько раз, пока программа не заканчивается, когда функция используется и Я не пишу 'word1', он говорит: «ничего не найдено». Например, если я набираю: word1, я получаю: «word1 contains», если я набираю: word2, я получаю: «ничего не найдено», если я набираю: word3, я получаю: «ничего не найдено», если я снова набираю word1, я получаю: «word1 содержит». поэтому он работает только для 1-го условия, после этого все остальные игнорируются. – Philkav

+0

Ха, я как-то неправильно читаю ваш код ... вы хотите найти все вхождения. Я отредактирую свой ответ. – liori

1

Здесь как бы я это сделать:

contains(Words) :- 
    findall(Word,has(Words,Word),Sols), 
    print_result(Sols). 

% Word is a target word in the list Words 
has(Words,Word) :- 
    member(Word,Words), 
    member(Word,[word1,word2,word3]). 

print_result([]) :- write('Nothing found.\n'). 
print_result([X|Xs]) :- print_sols([X|Xs]). 

print_sols([]). 
print_sols([X|Xs]) :- 
    concat(X, ' contained.\n',Output), 
    write(Output), 
    print_sols(Xs). 

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

Трюк с предикатом has, который использует member/2 дважды; один раз, чтобы выбрать элемент из списка ввода, и второй раз, чтобы проверить, что это одно из целевых слов. Используя это как аргумент findall/3, вы получите все целевые слова, которые были найдены во входном списке.

Примечание: [X|Xs] в print_results просто избегает необходимости использования разреза в первом предложении.

0

Я думаю, что у liori есть лучший ответ. Вот несколько иной подход, который может иметь смысл в некоторых случаях, т. Е.:

  • генерировать распечатку из
  • , если распечатка является пустым, то не печатать «ничего», в противном случае выход распечатка

следующие работы в SWI-Prolog и, вероятно, не в других Prologs, поскольку он использует with_output_to/2:

% Define what are the keywords 
keyword(word1). 
keyword(word2). 
keyword(word3). 

% Define how the found keywords are pretty-printed 
print_keyword(W) :- 
    format("Found: ~w.~n", [W]). 

% Generate a print-out and output it unless its empty 
print_keywords(Words) :- 
    with_output_to(atom(PrintOut), 
        forall((member(W, Words), keyword(W)), print_keyword(W))), 
    (
     PrintOut == '' 
    -> 
     writeln('Nothing found.') 
    ; 
     write(PrintOut) 
    ).