Как заставить правило возвращать все детали факта с помощью Prolog

#prolog

#prolog

Вопрос:

Используя Prolog, я сначала создал два факта, называемых grade и food: первый факт — это grade (X, Y), где X — ученик (Роб или Мэтт), а Y — уровень оценки (первокурсник или второкурсник). Второй факт — это еда (X, Y), где X — ученик (Роб или Мэтт), а Y — еда (пицца, бургер, паста, обертка).

Я создал правило с именем preference(X, Y), где X — это студент (Роб или Мэтт), а Y — предпочтения студентов.

Я хочу войти preference(rob,X). в GNU Prolog и вернуть его:

второкурсник, пицца, бургер.

Тем не менее, оно продолжает возвращаться: второкурсник, пицца, пицца.

Как мне решить эту проблему? Я потратил часы на изучение этого. Спасибо

Это код, который у меня есть:

 grade(rob, sophomore).
grade(matt, freshman).
food(rob, pizza).
food(rob, burger).
food(matt, pasta).
food(matt, wrap).

preference(X,Y):-
   grade(X,A),
   food(X,B),
   food(X,C),
   Y = (A, B, C).
 

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

1. Просто хочу убедиться, что я понял вопрос: почему вы хотите Y , чтобы в нем были и еда, и оценка preference ?

2. Я хотел бы сначала вернуть уровень оценки, а затем оба продукта, потому что Роб любит пиццу и бургер. Я не могу заставить его возвращать только пиццу.

Ответ №1:

То, как вы определили свои факты, приятно. Способ запроса не является обычным. Вот как я бы это сделал. Правило «предпочтений» проще:

 grade(rob, sophomore).
grade(matt, freshman).

food(rob, pizza).
food(rob, burger).
food(matt, pasta).
food(matt, wrap).

preference(X, A, Y):-
   grade(X, A),
   food(X, Y).
 

Вы обычно запрашиваете базу данных и получаете все решения с обратным отслеживанием:

 ?- preference(rob, Grade, Food).
Grade = sophomore,
Food = pizza ;
Grade = sophomore,
Food = burger.
 

Если вы хотите собрать продукты, вы можете использовать bagof / setof, например:

 ?- bagof(Food, preference(rob, Grade, Food), Foods).
Grade = sophomore,
Foods = [pizza, burger].
 

Что, если вы хотите запросить всех первокурсников?

 ?- bagof(Food, preference(Person, freshman, Food), Foods).
Person = matt,
Foods = [pasta, wrap].
 

Ответ №2:

Вам нужно указать, что значение B и C различны; для простоты я использую несколько способов ==/2 (документация):

 preference(X,Y):-
   grade(X,A),
   food(X,B),
   food(X,C),
   B==C,
   Y = (A, B, C).
 

Выдает вывод

 | ?- preference(X,Y).                             

X = rob
Y = (sophomore,pizza,burger) ? ;

X = rob
Y = (sophomore,burger,pizza) ? ;

X = matt
Y = (freshman,pasta,wrap) ? ;

X = matt
Y = (freshman,wrap,pasta) ? ;

no
 

Если вы не хотите, чтобы записи в основном были удвоены, вы можете использовать (в данном случае лексическое) «меньше» @</2 :

 preference(X,Y):-
   grade(X,A),
   food(X,B),
   food(X,C),
   B @< C,
   Y = (A, B, C).

| ?- preference(X,Y).                             

X = rob
Y = (sophomore,burger,pizza) ? ;

X = matt
Y = (freshman,pasta,wrap) ? ;

no
 

Ответ №3:

Возможно, я ошибаюсь, но я подозреваю, что это может быть неправильным пониманием prolog в целом в дополнение к неинтуитивному REPL. На самом деле Prolog не «возвращает» значение, он просто пытается сопоставить переменные со значениями, которые делают ваши предикаты истинными, и я был бы готов поспорить, что вы нажмете enter после того, как увидите первый результат.

Способ preference в настоящее время написан B и C будет соответствовать любым двум продуктам, с которыми rob он связан. Это может быть pizza, pizza или pizza, burger или burger, pizza , или так далее. Он не проверяет, равны ли B и C . Когда я запускаю preference(rob,X). prolog, он не только выдает мне первый результат, ЕСЛИ я не нажму enter.

 | ?- preference(rob,X).

X = (sophomore,pizza,pizza) ? ?
Action (; for next solution, a for all solutions, RET to stop) ?
 

Если вы нажмете a (или отправите спам ; несколько раз), prolog выдаст вам остальные результаты.

 | ?- preference(rob,X).

X = (sophomore,pizza,pizza) ? a

X = (sophomore,pizza,burger)

X = (sophomore,burger,pizza)

X = (sophomore,burger,burger)

yes
| ?-
 

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

 | ?- food(rob, X).

X = pizza ? a

X = burger

yes
| ?-