Ответ в теме: Разделить список на положительные, отрицательные и нулевый элементы

      Комментарии к записи Ответ в теме: Разделить список на положительные, отрицательные и нулевый элементы отключены

Главная Форумы Программирование Помощь с решением задач на Prolog Задачи на списки Разделить список на положительные, отрицательные и нулевый элементы Ответ в теме: Разделить список на положительные, отрицательные и нулевый элементы

#2287

У Вас выполняется одна лишняя проверка, т.к. если в списке есть первый элемент (список не пуст), который не является положительным или отрицательным, то он однозначно является нулевым. Однако, убрать проверку просто так нельзя, т.к. при этом интерпретатор будет искать в этом правиле другие решения для случая, когда элемент является положительным, например (предикат не является детерминированным). Проблему можно решить за счет использования отсечения.
Кроме того, можно изменить порядок правил так, чтобы проверка на ноль была не последней – тогда вместо сравнения можно использовать механизм сопоставления с образцом.

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

divide_positive_negative_zero([Head|Tail],[Head|TailPostive],Negative,Zero):-
  Head>0,!,
  divide_positive_negative_zero(Tail,TailPostive,Negative,Zero).
divide_positive_negative_zero([0|Tail],Postive,Negative,[0|TailZero]):-
  !,divide_positive_negative_zero(Tail,Postive,Negative,TailZero).
divide_positive_negative_zero([Head|Tail],Postive,[Head|TailNegative],Zero):-
  divide_positive_negative_zero(Tail,Postive,TailNegative,Zero).
divide_positive_negative_zero([],[],[],[]).

В диалектах пролога, соответствующих международному стандарту (ISO) есть встроенная функция include, позволяющая выбрать из списка элементы, соответствующие некоторому правилу. В качестве правила при этом можно передавать либо функцию, выполняющую сравнение числа с нулем, либо лямбду, либо оператор сравнения с заданным первым аргументом. В последнем случае используется механизм каррирования:

divide_positive_negative_zero(List, Postive, Negative, Zero):-
  include(<(0), List, Postive),
  include(>(0), List, Negative),
  include(=(0), List, Zero).