Recursion in Prolog: Addition to variables - recursion

I don't really understand how recursion works in Prolog. Assume you have the following two functions:
my_length([],0).
my_length([_|T], Length) :-
my_length(T, T_length),
Length is T_length + 1.
my_nth0(Position, [Element|_], Element, Position).
my_nth0(Position, [_|Tail], X, CurrentPos) :-
NextPos is CurrentPos + 1,
my_nth0(Position, Tail, X, NextPos).
I understand my_nth0: every time you call the function recursively, you increase NextPos by 1. However, I don't understsand my_length. I'd write it like this:
my_length([],0).
my_length([_|T], Length) :-
T_Length is Length + 1.,
my_length(T, T_length).
That seems to follow the same style as my_nth0. However, the first function implementation, which seems to be correct, does exactly the opposite (it basically says T_length is Length - 1). Why does this work?

Read the second clause of my_length/2 right-to-left!
If the length of T is T_length
then the length of [_|T] is T_length+1.

Did you actually try out your version of my_length/2 to see what happens? After you fix your syntax error (:)), you'll get a 'variable not instantiated error' if you query, my_length([1,2,3], N). because it will attempt to evaluate T_Length is Length + 1 when Length doesn't have a value. Thus, the recursive call has to come first if you use is/2 so that Length has a value from the recursive call as in the first example.
In addition, in your example, you are attempting to increase the variable via T_Length is Length + 1 but your recursive base case ends up with a length of 0. You cannot "grow" the length to 0.
my_length([], 0). % Base case is length = 0
my_length([_|T], Length) :-
% Length is UNINSTANTIATED on my_length([1,2,3], N) query
% so the following 'is/2' will fail to evaluate
T_Length is Length + 1,
my_length(T, T_length). % T_length > Length, but base case is 0!
Alternatively, if you used CLPFD and fix the order of evaluation of Length versus T_Length, you can put it in the order that you are showing:
my_length([], 0).
my_length([_|T], Length) :-
% The following defines an arithmetic 'relation' between Length and T_Length
% and is permitted as a constraint
Length #= T_Length + 1,
my_length(T, T_length).
You could also do the length using an accumulator to get the tail recursion so that you can indeed grow the length value until it reaches the end:
my_length(L, N) :-
my_length(L, 0, N).
my_length([], N, N). % Reached the length
my_length([_|T], A, N) :- % Here, `A` is instantiated by design
A1 is A + 1, % So this is/2 expression will evaluate
my_length(T, A1, N).

Related

Return values in Prolog

I'm supposed to write a predicate that does some math stuff. But I don't know how to pass numbers or return numbers.
Maybe you can give me an example?
Let's say a predicate divide/2 that takes two numbers a and b and returns a/b.
Yes, you pass numbers in in some arguments, and you get the result back in some other argument(s) (usually last). For example
divide( N, D, R) :-
R is N / D.
Trying:
112 ?- divide(100,5,X).
X = 20.
113 ?- divide(100,7,X).
X = 14.285714285714286.
Now, this predicate is divide/3, because it has three arguments: two for inputs and one for the output "information flow".
This is a simplified, restricted version of what a Prolog predicate can do. Which is, to not be that uni-directional.
I guess "return" is a vague term. Expression languages have expressions e-value-ated so a function's last expression's value becomes that function's "return" value; Prolog does not do that. But command-oriented languages return values by putting them into some special register. That's not much different conceptually from Prolog putting some value into some logvar.
Of course unification is more complex, and more versatile. But still, functions are relations too. Predicates "return" values by successfully unifying their arguments with them, or fail to do so, as shown in the other answer.
Prolog is all about unifying variables. Predicates don't return values, they just succeed or fail.
Typically when a predicate is expected to produce values based on some of the arguments then the left-most arguments are inputs and the right-most are the outputs. However, many predicates work with allowing any argument to be an input and any to be a output.
Here's an example for multiply showing how it is used to perform divide.
multiply(X,Y,Z) :- number(X),number(Y),Z is X * Y.
multiply(X,Y,Z) :- number(X),number(Z),X \= 0,Y is Z / X.
multiply(X,Y,Z) :- number(Y),number(Z),Y \= 0,X is Z / Y.
Now I can query it like this:
?- multiply(5,9,X).
X = 45 .
But I can easily do divide:
?- multiply(5,X,9).
X = 1.8 .
It even fails if I try to do a division by 0:
?- multiply(X,0,9).
false.
Here's another approach. So let's say you have a list [22,24,34,66] and you want to divide each answer by the number 2. First we have the base predicate where if the list is empty and the number is zero so cut. Cut means to come out of the program or just stop don't go to the further predicates. The next predicate checks each Head of the list and divides it by the number A, meaning (2). And then we simply print the Answer. In order for it to go through each element of the list we send back the Tail [24,34,66] to redo the steps. So for the next step 24 becomes the Head and the remaining digits [34,66] become the Tail.
divideList([],0,0):-!.
divideList([H|T],A,Answer):-
Answer is H//A,
writeln(Answer),
divideList(T,A,_).
?- divideList([22,24,34,66],2,L).
OUTPUT:
11
12
17
33
Another simpler approach:
divideList([],_,[]).
divideList([H|T],A,[H1|L]):-
H1 is H//A,!,
divideList(T,A,L).
?-divideList([22,4,56,38],2,Answer).
Answer = [11, 2, 28, 19]

Sum, Average of elements and Count the occurence of elements in Lists in Prolog

how can I write three predicates in Prolog that do the following things:
1) Define the sum (X, N) predicate, which is true when N is the sum of integers from the list X.
2) Define the avg (X, N) predicate that calculates the arithmetic average of all elements of the list X, where N is the number of elements.
3) Define the predicate called count(X, Y, N), which is true if the list Y contains N element instances
X.
Could you give me the examples of them and explain to me why they work the way they do? I know there are dozens of sum and avg predicates here on Stack Overflow, but I can't really understand why they work.
Define the sum(X, N) predicate, which is true when N is the sum of integers from the list X.
You want to calculate the sum of the elements of a list. What would be the simplest instance of the problem? When the list is empty, the sum of its element is 0. How can we break down larger lists to get to the simple case? We can remove the first element of the list, calculate the sum of the remaining list, and then add the first element to the result.
This approach can be implemented with the following code:
% Simple case: Sum of the empty list
sum([], 0).
% Recursive case: Split list into first element X and remaining list XS
sum([X|XS], N) :- sum(XS, M), N is M + X.
Usage:
?- sum([1,2,3],6).
true.
?- sum([1,2,3],X).
X = 6.
The is operator does arithmetic evaluation of its right-hand side (reference), as opposed to treating M + X as a literal term. If you would use = instead of is, M + X would be treated as a literal term. You would then get the following output:
?- sum([1,2,3],6).
false.
?- sum([1,2,3],0+3+2+1).
true.
So for Prolog 6 and 0+3+2+1 are different terms, until you force arithmetic evaluation as done by is.
2) Define the avg (X, N) predicate that calculates the arithmetic average of all elements of the list X, where N is the number of elements.
This is not possible. If X is the list and N the number of elements, then the predicate has no way of outputting the average (unless you count printing the average as a side-effect, I don't think you want). To fix this, add another parameter A that represents the average: avg(X, N, A).
We can calculate the average by taking the sum of the list and dividing it by the length of the list:
avg(X, N, A) :- sum(X, S), length(X, N), A is S / N.
Usage:
?- avg([1,2,3],3,2).
true.
?- avg([1,2,3,4],N,X).
N = 4,
X = 2.5.
3) Define the predicate called count(X, Y, N), which is true if the list Y contains N element instances X.
I understand you want N to be the number of times that the number X occurs in the list Y. We can again break this down into a simple case and then try to break down the general case into smaller steps until we get to the simple case.
For an empty list, we know that X occurs zero times in that list. For a non-empty list, we can remove the first element and check of how often X occurs in the remaining list. If the first element if equal to X, then the total number of occurrences of X is one plus the number of occurrences in the remaining list. If the first element is not equal to X, then the total number of occurrences of X is equal to the number of occurrences in the remaining list.
This approach can be implemented with the following code:
% Simple case: The list is empty.
count(_, [], 0).
% Recursive case: First element is equal to X
count(X, [X|YS], N) :- count(X, YS, M), N is M + 1, !.
% Recursive case: First element is unequal to X
count(X, [Y|YS], N) :- X \= Y, count(X, YS, N).
We use _ for variables we do not care about. We could also write X instead of _, but Prolog would then give us a warning about an unused variable.
Usage:
?- count(1, [1,1,2,3], N).
N = 2.
?- count(2, [1,1,2,3], N).
N = 1.

Prolog: Multiplying 2 lists with 1 of them not instantiated?

I am trying to write a rule that can return the sum of the product of each element from two lists (same length).
Here is what I have right now:
sum(0, _, []).
sum(Result, [H1|T1], [H2|T2]) :-
sum(Remaining,T1, T2),
Remaining is Result - (H1*H2).
It won't work when one of the list is not instantiated. What changes I need to make in order to make the following possible?
sum([1,2],X,3).
X = [3,0].
Thanks.
What you are calculating is commonly referred to as a dot product (also known as scalar product or inner product).
You write you are not allowed to use libraries. That surely refers to external libraries---not to the standard library that is part of SWI Prolog, right?
The following predicate list_list_dotProduct/3 roughly corresponds to the code you implemented. It uses finite domain constraints (#>=)/2 and (#=)/2 to allow for non-unidirectional integer arithmetic:
:- use_module(library(clpfd)).
list_list_dotProduct([],[],0).
list_list_dotProduct([X|Xs],[Y|Ys],Sum) :-
X #>= 0,
Y #>= 0,
Sum #= X*Y + Sum0,
list_list_dotProduct(Xs,Ys,Sum0).
Consider the following query:
?- list_list_dotProduct([1,2],Xs,3), label(Xs).
Xs = [1, 1] ;
Xs = [3, 0].
As an added bonus, here's an alternative implementation that is based on the predefined predicates same_length/2, ins/2, and scalar_product/4:
list_list_dotProduct(Xs,Ys,Prod) :-
same_length(Xs,Ys),
Xs ins 0..sup,
Ys ins 0..sup,
scalar_product(Xs,Ys,#=,Prod).

Prolog query fails

This is supposed to calculate the sum of two lists. The lists can be of different size.
sum([],[],[]).
sum(A,[],A).
sum([],B,B).
sum([A|Int1],[B|Int2],[C|Int3]) :-
(
C =:= A + B
;
((C =:= A), B = [])
;
((C =:= B), A = [])
),
sum(Int1,Int2,Int3).
It seems to work correctly, except when trying to find the sum of two lists. Then it gives the following error:
ERROR: =:=/2: Arguments are not sufficiently instantiated
I don't see why. There's a recursive and a basis step, what exactly is not yet instantiated and how do I fix it?
[1] While your disjunctions in the last clause are -- to some extent -- conceptually correct, Prolog considers these disjunctions in sequence. So it first considers C =:= A + B. But either A or B can be the empty list! This is what causes the error you reported, since the empty list is not allowed to occur in a numeric operation.
[2] You need to use C is A + b (assignment) i.o. C =:= A + B (numeric equivalence).
[3] If you say [A|Int1] and then A = [], then this means that [A|Int1] is not (only) a list of integers (as you claim it is) but (also) a list of lists! You probably intend to check whether the first or the second list is empty, not whether either contains the empty list.
Staying close to your original program, I would suggest to reorder and change things in the following way:
sumOf([], [], []):- !.
sumOf([], [B|Bs], [C|Cs]):- !,
C is B,
sumOf([], Bs, Cs).
sumOf([A|As], [], [C|Cs]):- !,
C is A,
sumOf(As, [], Cs).
sumOf([A|As], [B|Bs], [C|Cs]):-
C is A + B,
sumOf(As, Bs, Cs).
For example:
?- sumOf([1,2,3], [1,-90], X).
X = [2, -88, 3]
Notice my use of the cut (symbol !) in the above. This makes sure that the same answer is not given multiple times or -- more technically -- that no choicepoints are kept (and is called determinism).
You should read a tutorial or a book. Anyway, this is how you add two things to each other:
Result is A + B
This is how you could add all elements of one list:
sum([], 0). % because the sum of nothing is zero
sum([X|Xs], Sum) :-
sum(Xs, Sum0),
Sum is X + Sum0.
And this is how you could add the sums of a list of lists:
sums([], 0).
sums([L|Ls], Sums) :-
sums(Ls, Sums0),
sum(L, S),
Sums is Sums0 + S.

prolog recursive error (easy)

I'm new to prolog. I'm doing a recursive program the problem is that even though it prints the answer.. it doesn't stop after printing the answer and eventually gives "Out of local stack".
I've read it could be a left recursion issue but as I've already told you I'm new to prolog and I don't really understand what happens...
so.. here's code.
f(X, Y):-
Y is sqrt(1-((X-1)*(X-1))).
sum(SEGMENTS, 1, TOTAL):-
f(2/SEGMENTS*1,H1),
TOTAL is (2/SEGMENTS)*H1.
sum(SEGMENTS, NR, TOTAL):-
N1 is (NR-1),
sum(SEGMENTS, N1, S1),
f(2/SEGMENTS*NR,H1),
f(2/SEGMENTS*N1,H2),
TOTAL is S1 + (2/SEGMENTS)*((H1+H2)/2).
It's supposed to calculate a semicircle area with the trapezoid rule or something similar.
As I've already told you .. it does finishes but after getting to the base case sum(segments, 1, total) it calls the function with the second alternative... :S
Thanks guys!
Also: Here's what I get when I run it
?- sum(3000,3000,TOTAL).
TOTAL = 1.5707983753431007 ;
ERROR: Out of local stack
The problem is that backtracking will attempt the case of NR value of 1 on the second sum clause after the first clause has succeeded. This causes a long recursion process (since NR is being decremented continually for each recursive call, attempting to wrap around through all negative integer values, etc).
A simple way to resolve the problem is in your second sum clause. Since the intention is that it is for the case of NR > 1, put NR > 1 as your first statement:
sum(SEGMENTS, NR, TOTAL) :-
NR > 1,
N1 is (NR-1),
sum(SEGMENTS, N1, S1),
f(2/SEGMENTS*NR,H1),
f(2/SEGMENTS*N1,H2),
TOTAL is S1 + (2/SEGMENTS)*((H1+H2)/2).
Also note that the expression f(2/SEGMENTS*NR, H1) doesn't compute the expression 2/SEGMENTS*NR and pass it to f. It actually passes that expression symbolically. It just happens to work here because f includes it on the right hand side of an is/2 so it is evaluated as desired. If you trace it, you'll see what I mean.

Resources