Reputation: 3
I need to write a rule that replaces every negative number from a list with 0. This is my code:
neg_to_0(L,R) :-
(
nth1(X,L,E),
E<0,
replace(E,0,L,L2),
neg_to_0(L2,R2)
) ;
R = L.
replace(_, _, [], []).
replace(O, R, [O|T], [R|T2]) :- replace(O, R, T, T2).
replace(O, R, [H|T], [H|T2]) :- H \= O, replace(O, R, T, T2).
I have a rule "replace" which takes the element that needs to be replaced with 0 and returns the new list, but it stops after the rule replaces the values and return the new list, so i made the function to recall the main function with the new data so it can replace the other negative values :
replace(E,0,L,L2),
neg_to_0(L2,R2)
);
R = L.
On the last iteration, when it could not detect any negative numbers, i made it so that it saves the last correct list, but i only get back a "True" instead of the correct list.
Upvotes: 0
Views: 314
Reputation: 74325
Your code seems... awfully complex.
You seem to be trying to write procedural (imperative) code. Prolog is not an imperative language: one describes "truth" and lets Prolog's "inference engine" figure it out. And, pretty much everything is recursive by nature in Prolog.
So, for your problem, we have just a few simple cases:
The empty list []
, in which case, the transformed list is... the empty list.
A non-empty list. [N|Ns]
breaks it up into its head (N
) and its tail (Ns
). If N < 0, we replace it with 0; otherwise we keep it as-is. And then we recurse down on the tail.
To replace negative numbers in a list with zero, you don't need much more than this:
%
% negatives_to_zero/2 replaces negative numbers with 0
%
negatives_to_zero( [] , [] ) . % nothing to do for the empty list
negatives_to_zero( [N|Ns] , [M|Ms] ) :- % for a non-empty list,
M is max(N,0), % get the max of N and 0,
negatives_to_zero(Ns,Ms). % and recurse down on the tail
You can easily generalize this, of course to clamp numbers or lists of numbers, and constrain them to lie within a specified range:
%--------------------------------------------------------------------------------
% clamp( N , Min, Max, R )
%
% Constrain N such that Min <= N <= Max, returning R
%
% Use -inf (negative infinity) to indicate an open lower limit
% Use +inf (infinity) or +inf (positive infinity) to indicate an open upper limit
% -------------------------------------------------------------------------------
clamp( Ns , -inf , +inf , Ns ) .
clamp( N , Min , Max , R ) :- number(N) , clamp_n(N,Min,Max,R).
clamp( Ns , Min , Max , Rs ) :- listish(Ns) , clamp_l(Ns,Min,Max,Rs).
clamp_n( N , _ , _ , R ) :- \+number(N), !, R = N.
clamp_n( N , Min , Max , R ) :- T is max(N,Min), R is min(T,Max).
clamp_l( [] , _ , _ , [] ) .
clamp_l( [X|Xs] , Min , Max , [Y|Ys] ) :- clamp_n(X,Min,Max,Y), clamp(Xs,Min,Max,Ys).
listish( T ) :- var(T), !, fail.
listish( [] ) .
listish( [_|_] ) .
Upvotes: 1