2015-11-25 2 views
3

Я недавно начал изучать пролог, и столкнулся с проблемой с этим вопросом:Определите правило, чтобы определить, если список содержит данный член

Определите правило, чтобы определить, если список содержит указанный элемент.

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

Мой подход:

Iterative over the list and see if your member matches with head: 

on(Item,[Item|Rest]). /* is my target item on the list */ 

on(Item,[DisregardHead|Tail]):- 


      on(Item,Tail). 

Как вы думаете, что мой подход является правильным?

ответ

3

Да, ваше решение правильное и работает во всех направлениях. Ницца!

Примечания:

  1. Ваше решение является на самом деле более общей, чем просит задача. Это хорошая вещь! Задача, на мой взгляд, плохо сформулирована. Прежде всего, первое положение не является правилом , но фактом. Было бы лучше сформулировать задачу, например: «Напишите программу Prolog, которая является истиной , если термин имеет место в списке». Это оставляет открытым другие варианты использования, что хорошее решение будет также автоматически решить, например, , производя решений.
  2. Этот общий предикат широко известен как member/2. Как и ваше решение, оно также работает во всех направлениях. Попробуйте, например, ?- member(E, Ls).
  3. Имя для предиката может быть лучше. Хорошее соглашение об именах для Prolog позволяет понять, что означает каждый аргумент. Рассмотрим, например: element_list/2, и начните оттуда.
+1

Спасибо :) Ваши комментарии очень полезны. – python

5

То, что у вас есть, действительно является «правильной» реализацией. Стандартное имя для предиката, который составляет member/2, и доступно (под этим именем) в любом Прологе, и его нужно легко найти, как только вы узнаете его имя.

Некоторые примечания к сведению. Во-первых, с классическим определением (это именно так, как в «Искусство Пролог» Стерлинг и Шапиро, р 58, и идентичны с вашими.):

member_classic(X, [X|Xs]). 
member_classic(X, [Y|Ys]) :- 
    member_classic(X, Ys). 

Если вы пытаетесь скомпилировать это, вы получите одиночные ошибки. Это связано с тем, что вы указали переменные, которые появляются только один раз в своей области: Xs в первом разделе и Y во втором. Это в стороне, вот что делает программа:

?- member_classic(c, [a,b,c,x]). 
true ; 
false. 

?- member_classic(c, [c]). 
true ; 
false. 

?- member_classic(X, [a,b,c]). 
X = a ; 
X = b ; 
X = c ; 
false. 

Другими словами, с этим определением, Пролог оставит позади точки выбора, даже если совершенно очевидно, что не может быть дальнейшие решения (потому что в конец списка). Один из способов избежать этого - использовать технику, называемую «запаздыванием», как показано на рисунке SWI-Prolog library implementation of member/2.

И еще одно: с вашей текущей постановки задачи, может быть, что это считается нежелательным поведением:

?- member_classic(a, [a,a,a]). 
true ; 
true ; 
true ; 
false. 

Существует еще один предикат обычно называется member_check/2 или memberchk/2, который делает точно, что вы написали, а именно, успех или неудачу ровно один раз:

?- memberchk(a, [a,a,a]). 
true. 

?- memberchk(a, [x,y,z]). 
false. 

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

?- memberchk(X, [a,b,c]). 
X = a. % no more solutions! 

Есть допустимые варианты использования как member/2 и memberchk/2 ИМХО (но достаточно интересно, некоторые люди могли бы утверждать обратное).

Смежные вопросы