Предикат для фильтрации неконстантных значений из списка

#prolog

#prolog

Вопрос:

Я работаю над предикатом only_atoms /2 (список , результат-), который я хотел бы фильтровать неатомами.

Например :

 only_atoms([1, 2, X, h(Y), 'aba'], Result).
  

должен возвращать

 Result = [1, 2, 'aba'].
  

Меня не волнует порядок.

Вот фрагмент кода, который я придумал :

 only_atoms([], []) :- !.
only_atoms([Head | Tail], [Head | Result]) :-
    atom(Head),
    !,
    only_atoms(Tail, Result).
only_atoms([_ | Tail], Result) :-
    only_atoms(Tail, Result).
  

Я думал, что это правильное рассуждение для решения такой проблемы, но, похоже, оно неверно, поскольку оно дает мне [] (редактировать : на самом деле это дает [aba], см. Уточнения ниже, мой плохой !) несмотря ни на что. Я был бы признателен за помощь!

Ответ №1:

Первая подсказка: для 1 и 2 , atom возвращает false .

Кстати, я искал предикат filter, в стандартной библиотеке он вызывается include , обычно лучше, если вы используете то, что уже предоставляет язык 😉

 ?- include(atom, [1, 2, X, h(Y), 'aba'], Result).
Result = [aba].
  

или, если вы хотели просто отфильтровать переменные:

 ?- exclude(var, [1, 2, X, h(Y), 'aba'], Result).
Result = [1, 2, h(Y), aba].
  

Еще, кстати, одно любопытное различие между вашим only_atoms и использованием include(atom, ...) заключается в том, что ваш будет объединять переменные в первом списке с атомами во втором списке, тогда как include не будет.

 ?- only_atoms([1, x, 2, Y], [x, y]).
Y = y.

?- include(atom, [1, x, 2, Y], [x, y]).
false.
  

Эти тонкости пролога всегда меня удивляют (наверное, это потому, что я не уделял достаточно внимания в университете xD).

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

1. Хм, я смущен, я был уверен, что проверил atom на наличие констант и переменных. Затем я снова проверил типы данных в prolog и обнаружил, что числа и строки не были одинаковыми константами ~~ Спасибо, я просто добавил ;number (Head) после atom (Head), и это работает нормально. Еще раз извините за неудачные предположения; (

2. Я думал, что это было известно, и цель была ['aba'] единственной.

3. @Orbling — OP сообщал, что результатом был пустой список. Я не понимаю, как это решает эту конкретную проблему, но OP говорит, что это так, так что все хорошо, что хорошо заканчивается.

4. да, я действительно думал, что числа, атомы и так Далее Были константами и обрабатывались одинаково, поэтому мой пример кода был только числовым, а в этом, как оказалось, были атомы, это моя ошибка.

Ответ №2:

Вероятно, вам нужно заставить Head не быть атомом в предложении alternate, в противном случае это вариант и для атомов.

Это возвращает Result = ['aba'] для меня.

 only_atoms([], []).
only_atoms([Head | Tail], [Head | Result]) :- atom(Head), !, only_atoms(Tail, Result).
only_atoms([Head | Tail], Result) :-  atom(Head), !, only_atoms(Tail, Result).
  

В качестве альтернативы вы могли бы попробовать использовать findall/3 .

 atoms_list(List, Result) :- findall(Item, (member(Item, List), atom(Item)), Result).
  

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

1. Второе предложение имеет сокращение после atom(Head) . Разве это не помешало бы ему выполнить резервное копирование до третьего пункта, когда Head это атом?

2. да, обычно откат прерывается во втором предложении

3. @Тед Хопп: Я бы не хотел, чтобы он создавал резервную копию, если Head это атом. Если я удалю разрез, то выполнение будет ждать, чтобы проверить наличие альтернатив. С сокращением он мгновенно возвращается с определенным ответом.

4. Я не предлагал удалять разрез. Я задавался вопросом о необходимости принудительно Head не быть атомом в предложении alternate; он не может попасть туда, если Head не является атомом.