#prolog
#пролог
Вопрос:
Я только изучаю Prolog, и от меня требуется предоставить функции список, состоящий из положительных и отрицательных целых чисел, и она должна возвращать список подсписок таким образом, чтобы каждый подсписок состоял либо только из последовательных положительных чисел, либо только из последовательных отрицательных чисел. То, что я имею в виду, основано на знаке числа, присутствующего в списке, функция должна разбивать список.
Ниже приведены входные данные и требуемые выходные данные:
f([9,-10,-30,0,22,0,-40], L).
L = [[9], [-10, -30], [0, 22, 0], [-40]]
Чего я достиг до сих пор, так это:
f([],[]).
f([H|[]],L).
f([H,E|T],[[H,E|Tail1]|Tail]):-
H >=0,
E>=0,
f(T,[[Tail1]|Tail]).
f([H,E|T],[[H]|Tail]) :-
H>=0,
E<0,
f([E|T],Tail).
f([H,E|T],[[H,E|Tail1]|Tail]) :-
H<0,
E<0,
f(T,[[Tail1]|Tail]).
f([H,E|T],[[H]|Tail]) :-
H<0,
E>=0,
f([E|T],Tail).
Я получаю странную трассировку при запуске вышеупомянутой функции. Любая помощь была бы отличной. Спасибо 🙂
Комментарии:
1. Можете ли вы объяснить, что вы подразумеваете под «странным»? Выполняет ли ваш предикат (не функция) то, что вы хотите? Если нет, то что это на самом деле делает? Обратите внимание, что вам нужно переосмыслить
f([H|[]], L).
. ОбаH
иL
здесь являются одноэлементными, поэтому могут быть буквально чем угодно, и это предложение будет выполнено успешно. Итак,f([a], [1,2,3]).
успешно. Просто комментарий к обозначению:[H|[]]
может быть просто записан как[H]
.
Ответ №1:
Вы можете использовать fold/4
для разделения списка:
split(Input, LOutput):-
foldl(addorsplit, Input, state(_Sgn, LOutput), state(_, [[]])).
sgn(Num, Sgn):-
Sgn is sign(sign(Num)*2 1).
addorsplit(Item, state(Sgn, LOutput), state(NSgn, [Current|Tail])):-
sgn(Item, NSgn),
(Sgn = NSgn -> LOutput=[[Item|Current]|Tail] ; LOutput=[[],[Item|Current]|Tail]).
sgn/2
это вспомогательная процедура, позволяющая установить 0 на стороне положительных значений.
Пример запроса:
?- split([1,2,-3,-4,5,0,7],L).
L = [[1, 2], [-3, -4], [5, 0, 7]]
Использование clp (FD) позволит выполнять более общие запросы:
split2(Input, LOutput):-
foldl(addorsplit2, Input, state(_Sgn, LOutput), state(_, [[]])).
sgn2(Num, 1):-
Num #>= 0.
sgn2(Num, -1):-
Num #< 0.
addorsplit2(Item, state(Sgn, LOutput), state(NSgn, [Current|Tail])):-
sgn2(Item, NSgn),
(Sgn #= NSgn -> LOutput=[[Item|Current]|Tail] ; LOutput=[[],[Item|Current]|Tail]).
И теперь вы можете запросить, например:
?- split2([X,1,-3,Y],L).
L = [[X, 1], [-3], [Y]],
X in 0..sup,
Y in 0..sup ;
;
L = [[X, 1], [-3, Y]],
X in 0..sup,
Y in inf.. -1 ;
;
L = [[X], [1], [-3], [Y]],
X in inf.. -1,
Y in 0..sup ;
;
L = [[X], [1], [-3, Y]],
X in inf.. -1,
Y in inf.. -1 ;
Комментарии:
1. Вариант clpfd смешивает if-then-else с ограничениями, которые могут быть проблематичными,.. OTOH, 1 для умных
sign(sign(...)...)
.2. @repeat: итак, ваше предложение было бы использовать
if_/3
, верно? Почему это вообще проблематично?3. Я имел в виду общий случай. цели clpfd могут приводить к отложенным целям, которые в конечном итоге завершаются неудачей. В подобных ситуациях использование
(->)/2
может сделать поиск решений неполным.