Instantiate arguments in Prolog - prolog

Consider the PROLOG predicate f(list,integer) with flow model (i,o).
f([],0).
f([H|T],S):-
f(T,S1),
S1 is S-H.
Give the result of the evaluation f([1,2,3,4,5,6,7,8],S)?Justify the answer.
I've seen that we get the error "Arguments are not sufficiently instantied" and that is because the value of S is not updated in the end(only when the list is empty). Is this a good justification?

I've seen that we get the error "Arguments are not sufficiently
instantied" and that is because the value of S is not updated in the
end(only when the list is empty). Is this a good justification?
If this code is supposed to fail, yes.
The correct wording is:
This predicate is called with an unbound variable on second position, either at the top or recursively vai f(T,S1) (where S1 is fresh and thus unbound).
Then the arithmetic evaluation
S1 is S-H.
will have an unbound variable on the right-hand side of is/2 and cannot proceed (i.e. it will throw).
But note that it works if you switch to "constraint satisfaction over finite domains":
?- use_module(library(clpfd)).
true.
Then replacing is/2 by #=:
f([],0).
f([H|T],S):-
f(T,S1),
S1 #= S-H.
yields a working program:
?- f([1,2,3,4,5,6,7,8],S).
S = 36.

Related

Prolog-Splitting an algebraic expression using only "+" into separate lists of atoms and numbers

I am trying to create a predicate split_exp, which takes an algebraic expression that uses only "+" functor and generates two lists, one of the atoms and one of numbers. For example, 1+a+b+3 should generate [1,3] and [a,b]. The expression can be of any length.
I have tried.
split_exp(X,[X|[]],[]):-number(X).
split_exp(X,[],[X|[]]):-atom(X).
split_exp(X+Y,[X|Ns],Na):-number(X),split_exp(Y,Ns,Na).
split_exp(X+Y,Ns,[X|Na]):-atom(X),split_exp(Y,Ns,Na).
Kindly explain to me where i am going wrong in this implementation.
Should be easy to spot from your code, corrected and simplified:
split_exp(X,[X],[]):-number(X).
split_exp(X,[],[X]):-atom(X).
split_exp(Y+X,[X|Ns],As):-number(X),split_exp(Y,Ns,As).
split_exp(Y+X,Ns,[X|As]):-atom(X),split_exp(Y,Ns,As).
Note the recursive call, still using Y. Since (+)/2 is left associative (?- current_op(_,A,+) yields A=yfx as second result, since there is also the unary form), you must recurse on the left branch, which I did swapping X and Y subterms in the head(s).
You can show the expression shape using the ISO builtin ?- write_canonical(E) or ?- display(E).

Sums of the elements in list

I have to say that there is a similar quetion Sum of elements in list in Prolog needs little explanation, but still makes me confused.
Here is the following solution which needs some explanation.
sum([H],H).
sum([H|T],R):-sum(T,P),R is H + P.
Lets say we do sum([1,2,3],R).
sum([1,2,3],R)
sum([2,3],<unknown-1>)
sum([3],<unknown-2>)
so where it will fulfill the fact sum([H],H) ?
I do write the variable in sum([H],H), the only output for this case is 3,
which means that in the unknown-2 here is 3, why?
Just a beginner in prolog and any answers will be great appreciate.
The short answer: unification.
When, within the scope of a predicate clause, a variable name occurs more than once, all occurrences will be unified with each other. The predicate for unification is =/2, and is declared as operator, so =(A, A) and A = A mean the same. More importantly, this:
=(Term, Term).
is the definition of =/2 (see the documentation!)
In your example, you have a clause that says:
sum([H], H).
This means:
When the first argument of sum/2 is a list with exactly one element, the second argument of sum/2 is that element.
Because term unification is such a fundamental operation in Prolog, usually, it is not spelled out explicitly, as for example:
When the first argument of sum/2 is a list with exactly one element, that element and the second argument of sum/2 are unified with each other.
At least in the SWI-Prolog documentation, if unification is involved, it is usually described with "X is Y" instead of "X and Y are unified". See, for example, the documentation of min_member/2:
min_member(Min, List).
True when Min is the smallest member in the standard order of terms. Fails if List is empty.
It doesn't explicitly tell you that unification is used, and from that, the following behavior follows:
?- min_member(3, [1,2,X]).
X = 3.
I once asked a question about this because I found it too confusing.
By the way, with your current definition of sum/2, you can also get surprises because of the way that unification works. Look:
?- sum([1.5, 2.5], Sum).
Sum = 4.0 ; % unnecessary choice point but at least correct
false.
?- sum([1.5, 2.5], 4).
false. % Oops!
The SWI-Prolog library implementation suffers from the same problem:
?- sum_list([1.5, 2.5], Sum).
Sum = 4.0. % no choice point, at least
?- sum_list([1.5, 2.5], 4).
false. % Oops!
The work-around is to leave the second argument a free variable at first, and then use =:=/2, which does arithmetic comparison of numbers:
?- sum_list([1.5, 2.5], Sum), Sum =:= 4.
Sum = 4.0.
You can do this with your definition of sum/2 as well.
sumList([],0).
sumList([X|Tail],Sum):-
sumList(Tail,Sum1),
Sum is Sum1+X.

detailed meaning of ?- X is X+1

While studying the language Prolog I found the following true or false question:
In Prolog ?- X is X+1 results in the increment of the variable X by one.
A teacher said it's false, however I don't understand why. Won't X be X+1 from now on? Why is it false?
Prolog does not work with variables like elements that can change value. A variable is an element that currently has no value, once it has a value, it cannot change that value (except for backtracking in which the unification is undone).
In case X already has a value, X+1 will be calculated, but you cannot unify 3 with 4:
?- X=3, X is X+1.
false.
In case X is ungrounded at that moment, the is predicate will fail:
?- X is X+1.
ERROR: is/2: Arguments are not sufficiently instantiated
The question probably wants to demonstrate one of the fundamental differences between imperative programming and logic programming: in imperative programming a variable can be assigned a (new) value, in logic programming a variable can only grounded once (except for backtracking). Once fully grounded, you cannot ground it a different way.

Swi Prolog Relation

I am trying to write a relation split in Prolog that takes an integer N, a list L of integers, and other parameters, list L is flat. The relation split returns true if the list L can be divided into three subsets, such that the sum of the integers in each subset is strictly less than N. Otherwise, the relation returns false. This is the furthest I've gone so far:
split(list, list, list, list)
split([],[],[],[]).
list_sum([],0).
split([X|L], [X|L1], [X|L2], L3):-
list_sum([Head + Tail]),
list_sum>N,
!,
split(N, L,L1, L2, L3).
?- ERROR: toplevel: Undefined procedure: list_sum/2 (DWIM could not correct goal)
Any help and explanation is highly appreciated.
Basically your problem is that you need to go learn Prolog. I'm not kidding. You're going to fail your class if you think you can get away with this level of "not getting it" and pick up the rest on S.O.
What's that first line, a comment? Put the comment character there.
What is list_sum/2 doing there in the middle of your split/4 definition?
Unless you're trying to create some kind of difference list or destructuring arithmetic, [Head + Tail] will absolutely not do what you want.
What is list_sum>N supposed to mean on the next line? There is only one namespace in Prolog and the language is very, very dependent on getting your capitalization right. Being this sloppy does not bode well.
Why are you cutting on line 7?
Your last line is defining split/5 when the previous two rule heads (I think?) are defining split/4. This cannot be what you mean.
You're pattern-matching on line 4 requires that all three of the lists begin with the same value, which seems like a pretty special special-case considering you have no other in which you meaningfully examine the elements of the lists.
In my opinion this code is totally unsalvagable. Throw it away and start over. And read through a tutorial first.
To your exact question: you have not defined a predicate list_sum with two arguments in the "code" that you have shown. This is what the error is telling you.

Explanation of Prolog recursive procedure

I'd like someone to explain this procedure if possible (from the book 'learn prolog now'). It takes two numerals and adds them together.
add(0,Y,Y).
add(s(X),Y,s(Z)) :- add(X,Y,Z).
In principle I understand, but I have a few issues. Lets say I issue the query
?- add(s(s(0)), s(0), R).
Which results in:
R = s(s(s(0))).
Step 1 is the match with rule 2. Now X becomes s(0) and Y is still s(0). However Z (according to the book) becomes s(_G648), or s() with an uninstantiated variable inside it. Why is this?
On the final step the 1st rule is matched which ends the recursion. Here the contents of Y somehow end up in the uninstantiated part of what was Z! Very confusing, I need a plain english explanation.
First premises:
We have s(X) defined as the successor of X so basically s(X) = X+1
The _G### notation is used in the trace for internal variables used for the recursion
Let's first look at another definition of addition with successors that I find more intuitive:
add(0,Y,Y).
add(s(A),B,C) :- add(A,s(B),C).
this does basically the same but the recursion is easier to see:
we ask
add(s(s(0)),s(0),R).
Now in the first step prolog says thats equivalent to
add(s(0),s(s(0)),R)
because we have add(s(A),B,C) :- add(A,s(B),C) and if we look at the question A = s(0) and B=s(0). But this still doesn't terminate so we have to reapply that equivalency with A=0 and B=s(s(0)) so it becomes
add(0,s(s(s(0))),R)
which, given add(0,Y,Y). this means that
R = s(s(s(0)))
Your definition of add basically does the same but with two recursions:
First it runs the first argument down to 0 so it comes down to add(0,Y,Y):
add(s(s(0)),s(0),R)
with X=s(0), Y = s(0) and s(Z) = R and Z = _G001
add(s(0),s(0),_G001)
with X = 0, Y=s(0) and s(s(Z)) = s(G_001) = R and Z = _G002
add(0,s(0),_G002)
So now it knows that _G002 is s(0) from the definition add(0,Y,Y) but has to trace its steps back so _G001 is s(_G002) and R is s(_G001) is s(s(_G002)) is s(s(s(0))).
So the point is in order to get to the definition add(0,Y,Y) prolog has to introduce internal variables for a first recursion from which R is then evaluated in a second one.
If you want to understand the meaning of a Prolog program, you might concentrate first on what the relation describes. Then you might want to understand its termination properties.
If you go into the very details of a concrete execution as your question suggests, you will soon be lost in the multiplicity of details. After all, Prolog has two different interlaced control flows (AND- and OR-control) and in addition to that it has unification which subsumes parameter passing, assignment, comparison, and equation solving.
Brief: While computers execute a concrete query effortlessly for zillions of inferences, you will get tired after a screenful of them. You can't beat computers in that. Fortunately, there are better ways to understand a program.
For the meaning, look at the rule first. It reads:
add(s(X),Y,s(Z)) :- add(X,Y,Z).
See the :- in between? It is meant to symbolize an arrow. It is a bit unusual that the arrow points from right-to-left. In informal writing you would write it rather left-to-right. Read this as follows:
Provided, add(X,Y,Z) is true, then also add(s(X),Y,s(Z)) is true.
So we assume that we have already some add(X,Y,Z) meaning "X+Y=Z". And given that, we can conclude that also "(X+1)+Y=(Z+1)" holds.
After that you might be interested to understand it's termination properties. Let me make this very brief: To understand it, it suffices to look at the rule: The 2nd argument is only handed further on. Therefore: The second argument does not influence termination. And both the 1st and 3rd argument look the same. Therefore: They both influence termination in the same manner!
In fact, add/3 terminates, if either the 1st or the 3rd argument will not unify with s(_).
Find more about it in other answers tagged failure-slice, like:
Prolog successor notation yields incomplete result and infinite loop
But now to answer your question for add(s(s(0)), s(0), R). I only look at the first argument: Yes! This will terminate. That's it.
Let's divide the problem in three parts: the issues concerning instantiation of variables and the accumulator pattern which I use in a variation of that example:
add(0,Y,Y).
add(s(X),Y,Z):-add(X,s(Y),Z).
and a comment about your example that uses composition of substitutions.
What Prolog applies in order to see which rule (ie Horn clause) matches (whose head unifies) is the Unification Algorithm which tells, in particular, that if I have a variable, let's say, X and a funtor, ie, f(Y) those two term unify (there is a small part about the occurs check to...check but nevermind atm) hence there is a substitution that can let you convert one into another.
When your second rule is called, indeed R gets unified to s(Z). Do not be scared by the internal representation that Prolog gives to new, uninstantiated variables, it is simply a variable name (since it starts with '_') that stands for a code (Prolog must have a way to express constantly newly generated variables and so _G648, _G649, _G650 and so on).
When you call a Prolog procedure, the parameters you pass that are uninstantiated (R in this case) are used to contain the result of the procedure as it completes its execution, and it will contain the result since at some point during the procedure call it will be instantied to something (always through unification).
If at some point you have that a var, ie K is istantiated to s(H) (or s(_G567) if you prefer), it is still partilally instantiated and to have your complete output you need to recursively instantiate H.
To see what it will be instantiated to, have a read at the accumulator pattern paragraph and the sequent one, tho ways to deal with the problem.
The accumulator pattern is taken from functional programming and, in short, is a way to have a variable, the accumulator (in my case Y itself), that has the burden to carry the partial computations between some procedure calls. The pattern relies on recursion and has roughly this form:
The base step of the recursion (my first rule ie) says always that since you have reached the end of the computation you can copy the partial result (now total) from your accumulator variable to your output variable (this is the step in which, through unification your output var gets instantiated!)
The recursive step tells how to create a partial result and how to store it in the accumulator variable (in my case i 'increment' Y). Note that in the recursive step the output variable is never changed.
Finally, concerning your exemple, it follows another pattern, the composition of substitutions which I think you can understand better having thought about accumulator and instantiation via unification.
Its base step is the same as the accumulator pattern but Y never changes in the recursive step while Z does
It uses to unify the variable in Z with Y by partially instantiating all the computation at the end of each recursive call after you've reached the base step and each procedure call is ending. So at the end of the first call the inner free var in Z has been substituted by unification many times by the value in Y.
Note the code below, after you have reached the bottom call, the procedure call stack starts to pop and your partial vars (S1, S2, S3 for semplicity) gets unified until R gets fully instantiated
Here is the stack trace:
add(s(s(s(0))),s(0),S1). ^ S1=s(S2)=s(s(s(s(0))))
add( s(s(0)) ,s(0),S2). | S2=s(S3)=s(s(s(0)))
add( s(0) ,s(0),S3). | S3=s(S4)=s(s(0))
add( 0 ,s(0),S4). | S4=s(0)
add( 0 ,s(0),s(0)). ______|

Resources