#prolog
#пролог
Вопрос:
Мой запрос будет следующим:
separate([eat(chips),drink(water),eat(burger),eat(banana),drink(coke)],food,drink).
food = [eat(chips),eat(burger),eat(banana)]
drink = [drink(water),drink(coke)]
Я хочу разделить список, но я не смог понять, как это сделать.
separate(X,Cat1,Cat2):-
[Cat1|Cat2] = X,
Cat2 = X,
separate(X,Cat1,Cat2).
В настоящее время я могу использовать рекурсию только для просмотра каждого элемента списка, но я действительно не имею ни малейшего представления о том, как начать разделять их на отдельные списки.
Комментарии:
1. Вероятно, это повторяющийся вопрос, но я просто не хочу тратить время на его поиск.
2. @GuyCoder Чувствуешь себя ассистентом преподавателя, не так ли?
![]()
3. @DavidTonhofer
Feeling like a teaching assistant, are you?
Нет. Почему вы так говорите.4. @GuyCoder Потому что это то, что сказал бы TA.
Ответ №1:
Вы могли бы использовать операции фильтрации более высокого порядка, используя цель для фильтрации:
Например (обратите внимание, что переменные в Прологе должны начинаться с прописных букв):
separate(TaggedList,Food,Drink) :-
include(isFood,TaggedList,Food), % isFood/1 will be called for each element
include(isDrink,TaggedList,Drink). % same as above
isFood(eat(_)). % no need to be complex; just succeed if argument matches
isDrink(drink(_)). % same as above
И так:
?- separate(
[eat(chips),drink(water),eat(burger),eat(banana),drink(coke)],
Food,Drink).
Food = [eat(chips), eat(burger), eat(banana)],
Drink = [drink(water), drink(coke)].
Комментарии:
1. Это решение дважды пересекает список. Одним из вариантов было бы использовать раздел / 4 из той же библиотеки с одним из двух вспомогательных предикатов, которые вы показываете в своем решении.
2. @TA_intern Хорошая идея. Мне нужно запомнить.
partition/4
иpartition/5
.
Ответ №2:
Сопоставление с образцом. Вы хотите сопоставить шаблон.
Когда список продуктов питания и напитков пуст, у вас есть простой базовый предикат:
separate([],[],[]).
Когда вы хотите разделить еду и напитки, это так просто:
separate([eat(X)|T],[eat(X)|F],D) :- separate(T,F,D).
separate([drink(X)|T],F,[drink(X)|D]) :- separate(T,F,D).
Когда заголовок списка совпадает eat
, поместите элемент на первое место Food
списка. Когда drink
затем в Drink
списке. Просто.
Когда я запускаю это:
?- разделять ([есть (чипсы), пить (воду), есть (бургер), есть (банан), пить (кока-колу)], Еда, напиток). Еда = [есть (чипсы), есть (бургер), есть (банан)], Пить = [пить (вода), пить (кока-кола)].
Ответ №3:
Оба ответа хороши сами по себе. Другим вариантом для SWI-Prolog было бы использовать partition/4
следующее:
separate(List, Eats, Drinks) :-
partition(is_eat, List, Eats, Drinks).
is_eat(eat(_)).
Дополнительный кредит: почему это не работает?
?- partition(eat(_),
[eat(chips),drink(water),eat(burger),eat(banana),drink(coke)],
Eats, Drinks).