I have the following prolog program:
len([X],[Y],Count) :-
length(X,K),
length(Y,I),
K < I,
Count is 0
; I < K,
Count is 2
; I = K,
Count is 1.
When I enter :
len( [1,2], [5,2,4], X ).
I get: Singleton variable in branch: K and I
I looked up what this means here: http://www.swi-prolog.org/pldoc/man?section=singleton I tried doing _K & _I but you can only do that once.
This program should take two lists and compare the length of each list to determine the output value.
The first problem with your code is that the head of the clause has an error:
len([X],[Y],Count) :- ...
this means that the first and second list only can be singletons (lists with one element). So we need to rewrite this to:
len(X,Y,Count) :- ...
The second problem is that the ; has higher priority than ,, as a result the Prolog interpreter will interpret this as:
len(X,Y,Count) :-
(
length(X,K),
length(Y,I),
K < I,
Count is 0
);
(
I < K,
Count is 2
);
(
I = K,
Count is 1
).
So that means that in case the first condition fails, Prolog will backtrack, and now in that branch, it sees I < K, but for Prolog, those are new variables (since these are in a different branch). The Prolog interpreter will warn you that this is odd, especially in the case you write I < K, since it requires I and K to be grounded, so this will go wrong.
You need to rewrite your program to:
len(X,Y,Count) :-
length(X,K),
length(Y,I),
(
(
K < I,
Count is 0
);
(
I < K,
Count is 2
);
(
I = K,
Count is 1
)
).
or less verbose:
len(X,Y,Count) :-
length(X,K),
length(Y,I),
(
K < I,
Count is 0
; I < K,
Count is 2
; I = K,
Count is 1
).
But this is of course quite cumbersome. A more elegant solution is to write a compare/3 predicate first:
cmp(X,Y,0) :-
X < Y.
cmp(X,Y,2) :-
X > Y.
cmp(X,X,1).
and then write:
cmp(X,Y,0) :-
X < Y.
cmp(X,Y,2) :-
X > Y.
cmp(X,X,1).
len(X,Y,Cmp) :-
length(X,K),
length(Y,I),
cmp(K,I,Cmp).
Related
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.
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( [_|_] ) .
I'm new to prolog and doing so practice to pick it up. I'm confused at the moment with an error on line 5 saying Syntax error: Operator priority clash. This is probably due to the nesting of the logic, but I was wondering if there is a way to make this nesting work.
loopOver3(elt1, elt3, [H|T], sum):-
( =(elt1, elt2) =:= true ->
sum is sum + (elt1 + elt2),
; =(elt1, elt2) =\= false -> ( =(elt1, H) =:= true ->
sum is sum + (elt1 * H),
; =(elt1, H) =\= false -> ( =(elt2, H) =:= true ->
( \=(H, 0) =:= true ->
sum is sum + (100 / H)
)
)
)
)
loopOver3(elt1, elt3, T, sum).
Sudo code for what I'm trying to do:
for elt3 in list3:
if elt1 == elt2:
sum = sum + (elt1 + elt2)
else:
if elt1 == elt3:
sum = sum + (elt1 * elt3)
else:
if (elt2 == elt3) and (elt3 != 0):
sum = sum + (100 / elt3)
You have a bit of work to go to understand the concepts in Prolog. Your initial attempt is full of atoms (lowercase) rather than variables (uppercase). It's got mutability. You're thinking like Prolog has functions (it has predicates) that return values (they don't - they either succeed or fail).
I've made the assumption that you're peeling the first three values off of a list and then dropping the first item and recursing down.
So, if I have this list [1,2,1,2], I'd first be looking at [1,2,1] and then [2,1,2].
Or, in this longer example:
[1,2,1,2,2,1,1] => [1,2,1]
[2,1,2,2,1,1] => [2,1,2]
[1,2,2,1,1] => [1,2,2]
[2,2,1,1] => [2,2,1]
[2,1,1] => [2,1,1]
As soon as the list has only 2 elements I can then stop.
I'm assuming that each of the list of three values are your [Elt1, Elt2, Elt3].
To compute this we need to have an input list and an output sum, but to recurse down the list we need to have an accumulator to keep track of the current sum as we go. The first predicate is easy:
compute(List,Sum) :- compute(List,0,Sum).
Now, you have 5 predicates that we must match for.
the list containing 2 elements - we can return our accumulator
Elt1 = Elt2 then sum = sum + (elt1 + elt2)
Elt1 = Elt3 then sum = sum + (elt1 * elt3)
Elt2 = Elt3 and Elt3 \= 0 then sum = sum + (100 / elt3)
None of the above so we just pass along the current accumulator, i.e. sum = sum
compute([_,_],Sum,Sum).
compute([Elt1,Elt2,Elt3|Tail],AccNow,Sum) :-
Elt1 = Elt2,
!,
AccNext is AccNow + Elt1 + Elt2,
compute([Elt2,Elt3|Tail],AccNext,Sum).
compute([Elt1,Elt2,Elt3|Tail],AccNow,Sum) :-
Elt1 = Elt3,
!,
AccNext is AccNow + Elt1 * Elt3,
compute([Elt2,Elt3|Tail],AccNext,Sum).
compute([_,Elt2,Elt3|Tail],AccNow,Sum) :-
Elt3 \= 0,
Elt2 = Elt3,
!,
AccNext is AccNow + 100 / Elt3,
compute([Elt2,Elt3|Tail],AccNext,Sum).
compute([_,Elt2,Elt3|Tail],Acc,Sum) :-
compute([Elt2,Elt3|Tail],Acc,Sum).
If I try this on ?- compute([1,2,1,2],X). then I get X = 5. That's matching on the Elt1 = Elt3 predicate and giving me 0 + 1 * 1 and then again on the Elt1 = Elt3 predicate giving me 1 + 2 * 2 or 5.
If I try this on ?- compute([1,2,1,2,2,1,1],X). then I get X = 159. I'll leave it to you to see that it is the right result.
Just keep in mind that all Prolog is trying to do is succeed. If asked to prove a goal (i.e. compute/3) it finds the first predicate that matches and tries to prove that (by proving any subgoals) and when it fails it just backtracks to the previous choice point and tries another choice and to continue. If it proves the original goal then it succeed. If it didn't then it failed. There are no return values - only bound variables.
i have the next problem,
"return the numbers of natural numbers of an array"
ex. naturales(R,[6,-7,-4,3,2,8]).
R = 4
when a negative numbers appears return false and break my recursivity
naturales(R,[Head|Tail]):-naturales(R1,Tail), Head >= 0, R is R1+1.
naturales(0,[]).
Here is a very short solution :
naturales(In, Out) :-
aggregate(count,X^(member(X, In), X >= 0), Out).
If your predicate really needs to have only 2 arguments, one being the result, R, and the other one the given list, [H|T], you can do something like this. Note that the first predicate calls the second "naturales" with 3 arguments and then, that one starts the recursive process. The C is only a counter where you can add the number of positive elements and then copy that value to the result, in the last line of code. The first line just its just to make sure the empty list returns 0 positive elements. There is probably better ways to do this, this one is probably the most intuitive.
naturales(X, []):- X = 0.
naturales(R, [H|T]):- naturales(R, [H|T], 0).
naturales(R, [H|T], C):- (H > 0, C1 is C + 1, naturales(R1, T, C1), R = R1) ; naturales(R1, T, C), R = R1.
naturales(X, [], X).
A common prolog idiom is the use of a helper predicate with an accumulator (extra) variable. Try something like this:
natural_numbers( Xs, N ) :- natural_numbers( Xs, 0, N ).
natural_numbers( [] , N , N ) .
natural_numbers( [X|Xs] , T , N ) :-
( X > 0 -> T1 is T+1 ; T1 = T ) ,
natural_numbers( Xs, T1, N ).
As others pointed out, the recursive call cannot complete when there are negative numbers. So, you can just patch your program in this way
naturales(R,[Head|Tail]):-naturales(R1,Tail), (Head >= 0, R is R1+1 ; R=R1).
naturales(0,[]).
Now, nearly every Prolog out there (except mine :) implements (->)/2, also know as 'if-then-else'. So, the patch could also be written like
naturales(R,[Head|Tail]):-naturales(R1,Tail), (Head >= 0 -> R is R1+1 ; R=R1).
naturales(0,[]).
Given that naturales/2 is anyway not tail recursive (see #NicholasCarey answer for that), I think it has no practical relevance for you.
countdown(0, Y).
countdown(X, Y):-
append(Y, X, Y),
Y is Y-1,
countdown(X, Y).
So for this program i am trying to make a countdown program which will take Y a number and count down from say 3 to 0 while adding each number to a list so countdown(3, Y). should produce the result Y=[3,2,1]. I can't seem the end the recursion when i run this and i was wondering if anyone could help me?
I cant seem to get this code to work any help? I seem to be getting out of global stack so I dont understand how to end the recursion.
Your original code
countdown( 0 , Y ) .
countdown( X , Y ) :-
append(Y, X, Y),
Y is Y-1,
countdown(X, Y).
has some problems:
countdown(0,Y). doesn't unify Y with anything.
Y is Y-1 is trying to unify Y with the value of Y-1. In Prolog, variables, once bound to a value, cease to be variable: they become that with which they were unified. So if Y was a numeric value, Y is Y-1 would fail. If Y were a variable, depending on your Prolog implementation, it would either fail or throw an error.
You're never working with lists. You are expecting append(Y,X,Y) to magically produce a list.
A common Prolog idiom is to build lists as you recurse along. The tail of the list is passed along on each recursion and the list itself is incomplete. A complete list is one in which the last item is the atom [], denoting the empty list. While building a list this way, the last item is always a variable and the list won't be complete until the recursion succeeds. So, the simple solution is just to build the list as you recurse down:
countdown( 0 , [] ) . % The special case.
countdown( N , [N|Ns] ) :- % The general case: to count down from N...
N > 0 , % - N must be greater than 0.
N1 is N-1 , % - decrement N
countdown(N1,Ns) % - recurse down, with the original N prepended to the [incomplete] result list.
. % Easy!
You might note that this will succeed for countdown(0,L), producing L = []. You could fix it by changing up the rules a we bit. The special (terminating) case is a little different and the general case enforces a lower bound of N > 1 instead of N > 0.
countdown( 1 , [1] ) .
countdown( N , [N|Ns] ) :-
N > 1 ,
N1 is N-1 ,
countdown(N1,Ns)
.
If you really wanted to use append/3, you could. It introduces another common Prolog idiom: the concept of a helper predicate that carries state and does all the work. It is common for the helper predicate to have the same name as the "public" predicate, with a higher arity. Something like this:
countdown(N,L) :- % to count down from N to 1...
N > 0 , % - N must first be greater than 0,
countdown(N,[],L) % - then, we just invoke the helper with its accumulator seeded as the empty list
. % Easy!
Here, countdown/2 is our "public predicate. It calls countdown/3 to do the work. The additional argument carries the required state. That helper will look like something like this:
countdown( 0 , L , L ) . % once the countdown is complete, unify the accumulator with the result list
countdown( N , T , L ) . % otherwise...
N > 0 , % - if N is greater than 0
N1 is N-1 , % - decrement N
append(T,[N],T1) , % - append N to the accumulator (note that append/3 requires lists)
countdown(N1,T1,L) % - and recurse down.
. %
You might notice that using append/3 like this means that it iterates over the accumulator on each invocation, thus giving you O(N2) performance rather than the desired O(N) performance.
One way to avoid this is to just build the list in reverse order and reverse that at the very end. This requires just a single extra pass over the list, meaning you get O(2N) performance rather than O(N2) performance. That gives you this helper:
countdown( 0 , T , L ) :- % once the countdown is complete,
reverse(T,L) % reverse the accumulator and unify it with the result list
. %
countdown( N , T , L ) :- % otherwise...
N > 0 , % - if N is greater than 0
N1 is N-1 , % - decrement N
append(T,[N],T1) , % - append N to the accumulator (note that append/3 requires lists)
countdown(N1,T1,L) % - and recurse down.
. %
There are several errors in your code:
first clause does not unify Y.
second clause uses append with first and third argument Y, which would only succeed if X=[].
in that clause you are trying to unify Y with another value which will always fail.
Y should be a list (according to your comment) in the head but you are using it to unify an integer.
You might do it this way:
countdown(X, L):-
findall(Y, between(1, X, Y), R),
reverse(R, L).
between/3 will give you every number from 1 to X (backtracking). Therefore findall/3 can collect all the numbers. This will give you ascending order so we reverse/2 it to get the descending order.
If you want to code yourself recursively:
countdown(X, [X|Z]):-
X > 1,
Y is X-1,
countdown(Y, Z).
countdown(1, [1]).
Base case (clause 2) states that number 1 yields a list with item 1.
Recursive clause (first clause) states that if X is greater than 1 then the output list should contain X appended with the result from the recursive call.
So I am learning Prolog. I need to write a predicate that finds the min/max value of an integer list. For example, the query minmaxArray([4,-1,5,4,1,2,3,-2],X,Y) would return X = -2 Y = 5. Here is what I have so far:
%min/max element of a 1 item list is that item.
minmaxArray([X], X, X).
%when there is only 2 items, put the smaller element in A and the
%larger element in B
minmaxArray([X,Y], A, B) :- mymin(X,Y,Min),
A is Min, mymax(X,Y,Max), B is Max.
%when there is more than two items make a recursive call to find the min/max
%of the rest of the list.
minmaxArray([X,Y|T], A, B) :- minmaxArray([Y|T], M, K),
mymin(X,M,Temp), A is Temp, mymax(X,K,Temp2), B is Temp2.
Assume mymin and mymax predicates work properly. They return the min and max of 2 numbers.
The issue here is that for example when I query minmaxArray([4,-1,5],X,Y) it returns X = -1 Y = 5 and then again X = -1 Y = 5. I know this must be because it hits the 2nd condition on the recursive call. I only want it to return X = -1 Y = 5 one time. I tried replacing condition 3 with this:
minmaxArray([X,Y,_|T], A, B) :- minmaxArray([Y,_|T], M, K),
mymin(X,M,Temp), A is Temp, mymax(X,K,Temp2), B is Temp2.
but that crashes the program. What can I do to fix this?
Note: I know that I may not be using the terminology correctly by saying returning and saying predicate when it should be rule, etc so I apologize in advance.
Seems that your code could be simpler. This predicate does all what's needed, and attempt to show how to use some standard construct (if/then/else)
minmaxArray([X], X, X).
minmaxArray([X|R], Min, Max) :-
minmaxArray(R, Tmin, Tmax),
( X < Tmin -> Min = X ; Min = Tmin ), % or mymin(X,Tmin,Min)
( X > Tmax -> Max = X ; Max = Tmax ).
You have provided 2 ways of solving the case where there are 2 items: one explicitly for 2 items, and your general case, which then employs the 1 element case.
Solution: remove the unneeded 2-element case.
Or, tail-recursive:
minmax([X|Xs],Min,Max) :- % we can only find the min/max of a non-empty list.
minmax(Xs,(X,X),Min,Max) % invoke the helper with the min/max accumulators seeded with the first item
.
minmax([],(Min,Max),Min,Max). % when the source list is exhausted, we're done: unify the accumulators with the result
minmax([X|Xs],(M,N),Min,Max) :- % when the source list is non-empty
min(X,M,M1) , % - get a new min value for the accumulator
max(X,N,N1) , % - get a new max value for the accumulator
minmax(Xs,(M1,N1),Min,Max) % - recurse down on the tail.
.
min(X,Y,X) :- X =< Y . % X is the min if it's less than or equal to Y.
min(X,Y,Y) :- X > Y . % Y is the min if it's greater than X.
max(X,Y,X) :- X >= Y . % X is the max if it's greater than or equal to Y.
max(X,Y,Y) :- X < Y . % Y is the max if it's greater than X.