Defining the rule to avoid Arithmetic Error is/2 in Prolog - prolog

I'm trying to implement a binary tree in Prolog and I'm getting the following error:
ERROR: is/2: Arithmetic: `z/0' is not a function
I understand that this error occurs because the RHS of is/2 has not been instantiated properly.
But I'm finding it difficult to figure out how to instantiate my variable z in the second tree_eval/3 .
tree_eval(_,tree(empty,Num,empty),Num).
tree_eval(Value,tree(empty,z,empty),Value):-
z = Value.
tree_eval(Value,tree(L,Op,R),Eval):-
tree_eval(Value,L,LEval),
tree_eval(Value,R,REval),
eval(LEval,REval,Op,Eval).
eval(LEval,REval,Op,Result):-
Op = '+',
Result is LEval + REval.
eval(LEval,REval,Op,Result):-
Op = '-',
Result is LEval - REval.
eval(LEval,REval,Op,Result):-
Op ='/',
Result is LEval/REval.
How do I assign Value to z here?
Thanks in advance.

By z=Value you are actually unifying the variable Value with the atom z. If you mean z to be a variable you have to write it as a capital letter Z as #vmg pointed out:
tree_eval(Value,tree(empty,Z,empty),Value):-
Z = Value.
In that case it is interesting to consider what happens when querying the predicate:
?- tree_eval(V,tree(empty,3,empty),E).
E = 3 ? ;
E = V = 3 ? ;
no
The first solution is produced by your first rule in which you have an anonymous variable for the first argument. The second solution is produced by your second rule in which you demand the first and third arguments to be the same. So essentially you have two derivation paths for the value that is 3 in both cases. Now let's look at a slightly bigger tree:
?- tree_eval(V,tree(tree(empty,2,empty),+,tree(empty,3,empty)),E).
E = 5 ? ;
E = 5,
V = 3 ? ;
E = 5,
V = 2 ? ;
no
The first answer is hardly suprising as the tree evaluates to 5 indeed but what about the next two solutions? Let's take a look how prolog comes to these solutions: The term
tree(tree(empty,2,empty),+,tree(empty,3,empty))
matches only with the third rule because the subtrees are not empty. So tree_eval/3 is called with the subtree tree(empty,2,empty) and yields as first solution: (_,tree(empty,2,empty),2)
Then tree_eval/3 is called for the subtree tree(empty,3,empty) with the first solution: (_,tree(empty,3,empty),3)
Now eval(2,3,+,Eval) yields Eval=5. The first argument however is still Value=_. So the first solution for the query is: E=5.
If you ask for other answers prolog will try if there are further solutions for the 3rd goal, determine there are none, hence backtracking to the 2nd goal: the right subtree, and indeed your second rule delivers: (3,tree(empty,3,empty),3). eval(2,3,+,Eval) again contributes Eval=5, hence the second solution to the query: E=5, V=3.
If you still ask for more solutions prolog has to backtrack further to the 1st goal: and your 2nd rule delivers again: (2,tree(empty,2,empty),2). Now your second goal again matches the 1st rule: (_,tree(empty,3,empty),3), eval/4 delivers again Eval=5, so the 3rd solution to the query is: E=5, V=2
Backtracking one more time to goal 2 prolog is trying the 2nd rule again and fails because the first argument can't be 2 and 3 at the same time. So there is no 4th solution to the query.
However, if tree_eval/3 would be queried with the same tree structure but both leaves being 2 it is, by the above reasoning, not really suprising that there are 4 solutions:
?- tree_eval(V,tree(tree(empty,2,empty),+,tree(empty,2,empty)),E).
E = 4 ? ;
E = 4,
V = 2 ? ;
E = 4,
V = 2 ? ;
E = 4,
V = 2 ? ;
no
Looking at those multiple solutions it is apparent that your third argument is delivering the correct solution, and that you don't really need the first argument. You can also do without the second rule. Incorporating some improvements suggested by #mat, your predicate might then look something like that:
tree_evaluation(tree(empty,Num,empty),Num).
tree_evaluation(tree(L,Op,R),Val) :-
tree_evaluation(L,LVal),
tree_evaluation(R,RVal),
evaluation(LVal,RVal,Op,Val).
evaluation(L,R,+,V) :-
V is L + R.
evaluation(L,R,-,V) :-
V is L - R.
evaluation(L,R,/,V) :-
V is L / R.
This version yields unique answers:
?- tree_evaluation(tree(empty,3,empty),E).
E = 3 ? ;
no
?- tree_evaluation(tree(tree(empty,2,empty),+,tree(empty,3,empty)),E).
E = 5 ? ;
no

Related

Prolog, Dynamic Programming, Fibonacci series

I should preface this by saying this is a homework problem that I am having issues with, and Im not sure if that sort of thing is allowed around here, but I dont know where else to turn to. This is the question I've been asked:
In the sample code for this question, you can see a Fibonacci predicate fibSimple/2 which calculates the Fibonacci of X, a natural number. The problem with the naive recursive solution, is that you end up recalculating the same recursive case several times. See here for an explanation.
For example, working out the fib(5) involves working out the solution for fib(2) three separate times. A Dynamic Programming approach can solve this problem. Essentially, it boils down to starting with fib(2), then calculating fib(3), then fib(4) etc.... until you reach fib(X). You can store these answers in a list, with fib(X) ending up as the first item in the list.
Your base cases would look like the following:
fib(0,[0]).
fib(1,[1,0]).
Note the way that fib(1) is defined as [1,0]. fib(1) is really 1 but we are keeping a list of previous answers.
Why do we do this? Because to calculate fib(X), we just have to calculate fib(X-1) and add the first two elements together and insert them at the front of the list. For example, from the above, it is easy to calculate fib(2,Ans). fib(2) in this case would be [1,1,0]. Then fib(3) would be [2,1,1,0], fib(4) would be [3,2,1,1,0] etc....
Complete the fib/2 predicate as outlined above - the base cases are shown above. You need to figure out the one line that goes after the base cases to handle the recursion.
This is the sample code they provided
fibSimple(0,0). % fib of 0 is 0
fibSimple(1,1). % fib of 1 is 1
fibSimple(N,X) :- N>1,fibSimple(N-1,A), fibSimple(N-2,B), X is A+B.
fib(0,[0]).
fib(1,[1,0]).
I've had a few attempts at this, and while I'm fairly certain my attempt will end up being hopelessly wrong, this is what I have most recently tried
fib(X,[fib(X-2)+fib(X-1) | _]).
My reasoning to this is that if you can get the answer to the last 2, and add them together making them the first or "head" of the list, and then the underscore representing the rest.
My 2 issues are:
1) I don't know/think this underscore will do what I want it to do, and am lost in where to go from here
and
2) I don't know how to even run this program as the fib\2 predicate requires 2 parameters. And lets say for example I wanted to run fib\2 to find the fibonacci of 5, I would not know what to put as the 2nd parameter.
Because this is homework I will only sketch the solution - but it should answer the questions you asked.
A predicate differs from a function in that it has no return value. Prolog just tells you if it can derive it (*). So if you just ask if fib(5) is true the best you can get is "yes". But what are the Fibonacci numbers from 1 to 5 then? That's where the second argument comes in. Either you already know and check:
?- fib(5, [5, 3, 2, 1, 1, 0]).
true ; <--- Prolog can derive this fact. With ; I see more solutions.
false <--- no, there are no other solutions
Or you leave the second argument as a variable and Prolog will tell you what values that variable must have such that it can derive your query:
?- fib(5, X).
X = [5, 3, 2, 1, 1, 0] ;
false.
So the second argument contains the result you are looking for.
You can also ask the other queries like fib(X,Y) "which numbers and their fibonacci hostories can we derive?" or fib(X, [3 | _]) "which number computes the the fibonacci number 3?". In the second case, we used the underscore to say that the rest of the list does not matter. (2)
So what do we do with fib(X,[fib(X-2)+fib(X-1) | _]).? If we add it to the clauses for 0 and 1 you were given we can just query all results:
?- fib(X,Y).
X = 0,
Y = [1] ; <-- first solution X = 0, Y = [1]
X = 1,
Y = [1, 0] ; <-- second solution X = 1, Y = [1, 0]
Y = [fib(X-2)+fib(X-1)|_2088]. <-- third solution
The third solution just says: a list that begins with the term fib(X-2)+fib(X-1) is a valid solution (the _2088 as just a variable that was not named by you). But as mentioned in the beginning, this term is not evaluated. You would get similar results by defining fib(X, [quetzovercaotl(X-1) | _]).
So similar to fibSimple you need a rule that tells Prolog how to derive new facts from facts it already knows. I have reformatted fibSimple for you:
fibSimple(N,X) :-
N>1,
fibSimple(N-1,A),
fibSimple(N-2,B),
X is A+B.
This says if N > 1 and we can derive fibSimple(N-1,A) and we can derive fibSimple(N-2,B) and we can set X to the result of A + B, then we derive fibSimple(N, X). The difference to what you wrote is that fibSimple(N-1,A) occurs in the body of the rule. Again the argument N-1 does not get evaluated. What actually happens is that the recursion constructs the terms 3-1 and (3-1)-1) when called with the query fib(3,X). The actual evaluation happens in the arithmetic predicates is and <. For example, the recursive predicate stops when it tries to evaluate (3-1)-1 > 1 because 1>1 is not true. But we also do not hit the base case fibSimple(1, 1) because the term (3-1)-1 is not the same as 1 even though they evaluate to the same number.
This is the reason why Prolog does not find the Fibonacci number of 3 in the simple implementation:
?- fibSimple(3, X).
false.
The arithmetic evaluation is done by the is predicate: the query X is (3-1) -1 has exactly the solution X = 1. (3)
So fibSimple must actually look like this: (4)
fibSimple(0,1).
fibSimple(1,1).
fibSimple(N,X) :-
N>1,
M1 is N -1, % evaluate N - 1
M2 is N -2, % evaluate N - 2
fibSimple(M1,A),
fibSimple(M2,B),
X is A+B.
For fib you can use this as a template where you only need one recursive call because both A and B are in the history list. Be careful with the head of your clause: if X is the new value it can not also be the new history list. For example, the head could have the form fib(N, [X | Oldhistory]).
Good luck with the homework!
(1) This is a little simplified - Prolog will usually give you an answer substitution that tells you what values the variables in your query have. There are also some limited ways to deal with non-derivability but you don't need that here.
(2) If you use the arithmetic predicates is and > these two queries will not work with the straightforward implementation. The more declarative way of dealing with this is arithmetic constraints.
(3) For this evaluation to work, the right hand side of is may not contain variables. This is where you would need the arithmetic constraints from (2).
(4) Alternatively, the base cases could evaluate the arithmetic terms that were passed down:
fibSimple(X, 0) :-
0 is X.
fibSimple(X, 1) :-
1 is X.
fibSimple(N,X) :-
N>1,
fibSimple(N-1,A),
fibSimple(N-2,B),
X is A+B.
But this is less efficient because a single number takes much less space than the term 100000 - 1 - 1 -1 .... -1.

Defining a mathematical language in prolog

So I have this mathematical language, it goes like this:
E -> number
[+,E,E,E] //e.g. [+,1,2,3] is 1+2+3 %we can put 2 to infinite Es here.
[-,E,E,E] //e.g. [-,1,2,3] is 1-2-3 %we can put 2 to infinite Es here.
[*,E,E,E] //e.g. [*,1,2,3] is 1*2*3 %we can put 2 to infinite Es here.
[^,E,E] //e.g. [^,2,3] is 2^3
[sin,E] //e.g. [sin,0] is sin 0
[cos,E] //e.g. [cos,0] is cos 0
and I want to write the set of rules that finds the numeric value of a mathematical expression written by this language in prolog.
I first wrote a function called "check", it checks to see if the list is written in a right way according to the language we have :
check1([]).
check1([L|Ls]):- number(L),check1(Ls).
check([L|Ls]):-atom(L),check1(Ls).
now I need to write the function "evaluate" that takes a list that is an expression written by this language, and a variable that is the numeric value corresponding to this language.
example:
?-evaluate([*,1,[^,2,2],[*,2,[+,[sin,0],5]]]],N) -> N = 40
so I wrote this:
sum([],0).
sum([L|Ls],N):- not(is_list(L)),sum(Ls,No),N is No + L.
min([],0).
min([L|Ls],N):-not(is_list(L)), min(Ls,No),N is No - L.
pro([],0).
pro([X],[X]).
pro([L|Ls],N):-not(is_list(L)), pro(Ls,No), N is No * L.
pow([L|Ls],N):-not(is_list(L)), N is L ^ Ls.
sin_(L,N):-not(is_list(L)), N is sin(L).
cos_(L,N):-not(is_list(L)), N is cos(L).
d([],0).
d([L|Ls],N):- L == '+' ,sum(Ls,N);
L == '-',min(Ls,N);
L == '*',pro(Ls,N);
L == '^',pow(Ls,N);
L == 'sin',sin_(Ls,N);
L == 'cos',cos_(Ls,N).
evaluate([],0).
evaluate([L|Ls],N):-
is_list(L) , check(L) , d(L,N),L is N,evaluate(Ls,N);
is_list(L), not(check(L)) , evaluate(Ls,N);
not(is_list(L)),not(is_list(Ls)),check([L|Ls]),d([L|Ls],N),
L is N,evaluate(Ls,N);
is_list(Ls),evaluate(Ls,N).
and it's working for just a list and returning the right answer , but not for multiple lists inside the main list, how should my code be?
The specification you work with looks like a production rule that describes that E (presumably short for Expression) might be a number or one of the 6 specified operations. That is the empty list [] is not an expression. So the fact
evaluate([],0).
should not be in your code. Your predicate sum/2 almost works the way you wrote it, except for the empty list and a list with a single element, that are not valid inputs according to your specification. But the predicates min/2 and pro/2 are not correct. Consider the following examples:
?- sum([1,2,3],X).
X = 6 % <- correct
?- sum([1],X).
X = 1 % <- incorrect
?- sum([],X).
X = 0 % <- incorrect
?- min([1,2,3],X).
X = -6 % <- incorrect
?- pro([1,2,3],X).
X = 6 ? ; % <- correct
X = 0 % <- incorrect
Mathematically speaking, addition and multiplication are associative but subtraction is not. In programming languages all three of these operations are usually left associative (see e.g. Operator associativity) to yield the mathematically correct result. That is, the sequence of subtractions in the above query would be calculated:
1-2-3 = (1-2)-3 = -4
The way you define a sequence of these operations resembles the following calculation:
[A,B,C]: ((0 op C) op B) op A
That works out fine for addition:
[1,2,3]: ((0 + 3) + 2) + 1 = 6
But it doesn't for subtraction:
[1,2,3]: ((0 - 3) - 2) - 1 = -6
And it is responsible for the second, incorrect solution when multiplying:
[1,2,3]: ((0 * 3) * 2) * 1 = 0
There are also some other issues with your code (see e.g. #lurker's comments), however, I won't go into further detail on that. Instead, I suggest a predicate that adheres closely to the specifying production rule. Since the grammar is describing expressions and you want to know the corresponding values, let's call it expr_val/2. Now let's describe top-down what an expression can be: It can be a number:
expr_val(X,X) :-
number(X).
It can be an arbitrarily long sequence of additions or subtractions or multiplications respectively. For the reasons above all three sequences should be evaluated in a left associative way. So it's tempting to use one rule for all of them:
expr_val([Op|Es],V) :-
sequenceoperator(Op), % Op is one of the 3 operations
exprseq_op_val(Es,Op,V). % V is the result of a sequence of Ops
The power function is given as a list with three elements, the first being ^ and the others being expressions. So that rule is pretty straightforward:
expr_val([^,E1,E2],V) :-
expr_val(E1,V1),
expr_val(E2,V2),
V is V1^V2.
The expressions for sine and cosine are both lists with two elements, the first being sin or cos and the second being an expression. Note that the argument of sin and cos is the angle in radians. If the second argument of the list yields the angle in radians you can use sin/1 and cos/2 as you did in your code. However, if you get the angle in degrees, you need to convert it to radians first. I include the latter case as an example, use the one that fits your application.
expr_val([sin,E],V) :-
expr_val(E,V1),
V is sin(V1*pi/180). % radians = degrees*pi/180
expr_val([cos,E],V) :-
expr_val(E,V1),
V is cos(V1*pi/180). % radians = degrees*pi/180
For the second rule of expr_val/2 you need to define the three possible sequence operators:
sequenceoperator(+).
sequenceoperator(-).
sequenceoperator(*).
And subsequently the predicate exprseq_op_val/3. As the leading operator has already been removed from the list in expr_val/2, the list has to have at least two elements according to your specification. In order to evaluate the sequence in a left associative way the value of the head of the list is passed as an accumulator to another predicate exprseq_op_val_/4
exprseq_op_val([E1,E2|Es],Op,V) :-
expr_val(E1,V1),
exprseq_op_val_([E2|Es],Op,V,V1).
that is describing the actual evaluation. There are basically two cases: If the list is empty then, regardless of the operator, the accumulator holds the result. Otherwise the list has at least one element. In that case another predicate, op_val_args/4, delivers the result of the respective operation (Acc1) that is then recursively passed as an accumulator to exprseq_op_val_/4 alongside with the tail of the list (Es):
exprseq_op_val_([],_Op,V,V).
exprseq_op_val_([E1|Es],Op,V,Acc0) :-
expr_val(E1,V1),
op_val_args(Op,Acc1,Acc0,V1),
exprseq_op_val_(Es,Op,V,Acc1).
At last you have to define op_val_args/4, that is again pretty straightforward:
op_val_args(+,V,V1,V2) :-
V is V1+V2.
op_val_args(-,V,V1,V2) :-
V is V1-V2.
op_val_args(*,V,V1,V2) :-
V is V1*V2.
Now let's see how this works. First your example query:
?- expr_val([*,1,[^,2,2],[*,2,[+,[sin,0],5]]],V).
V = 40.0 ? ;
no
The simplest expression according to your specification is a number:
?- expr_val(-3.14,V).
V = -3.14 ? ;
no
The empty list is not an expression:
?- expr_val([],V).
no
The operators +, - and * need at least 2 arguments:
?- expr_val([-],V).
no
?- expr_val([+,1],V).
no
?- expr_val([*,1,2],V).
V = 2 ? ;
no
?- expr_val([-,1,2,3],V).
V = -4 ? ;
no
The power function has exactly two arguments:
?- expr_val([^,1,2,3],V).
no
?- expr_val([^,2,3],V).
V = 8 ? ;
no
?- expr_val([^,2],V).
no
?- expr_val([^],V).
no
And so on...

Prolog: Counting occurrences of an element in a list returning multiple answers

I'm having a bit of trouble with something. I've wrote a function that returns the number of occurrences of an element in a list. Here is the code:
occurencesHelp(X,[],N,N).
occurencesHelp(X,[X|T],N,Y) :-
N1 is N+1,
occurencesHelp(X,T,N1,Y).
occurencesHelp(X,[H|T],N,Y) :-
occurencesHelp(X,T,N,Y).
occurences(X,List,N) :-
occurencesHelp(X,List,0,N).
This works fine, the first answer I get is:
N = 5 ?
but then there are multiple answers such as:
N = 4 ? ;
N = 4 ? ;
N = 3 ? ;
N = 4 ? ;
N = 3 ? ;
and so on. I've tried tracing through to see if I can see why this is the case but can't figure it out. I think using a cut would help me, but we have been specifically told not to use cut, so that isn't an option. Any help would be appreciated.
Thanks.
When I load your code in SWI-Prolog, I get the following warnings:
Warning: /home/isabelle/occ.pl:1:
Singleton variables: [X]
Warning: /home/isabelle/occ.pl:7:
Singleton variables: [H]
These warnings are important. Singleton variables are very often a sign that you have made a serious logical error. In your case, let's look at line 7. It's in this clause:
occurencesHelp(X,[H|T],N,Y) :-
occurencesHelp(X,T,N,Y).
Prolog tells us that H is a singleton variable. This means that it only occurs once in this clause, and this means that we forgot to put H in a relation with the other variables.
The previous clause says (procedurally): "if the head of the list is X, increment the counter". Conversely, this clause should say: "if the head of the list is not X, keep the counter unchanged". But it does not say that about the head of the list: In fact, it doesn't say anything about H (hence the warning).
So what you need to add is a goal expressing the fact that X and H should be unequal. Two ways to express this are X \= H and dif(X, H). In your case, the choice depends on what you have already learned in your course.
(The singleton warning for line 1 is benign in this case; you can just replace X by _X to tell Prolog that you explicitly want to ignore that variable.)

Prolog Set List's Head

append([],U,U).
append([X|U1],U2,[W|U3]) :- **W = X** , append(U1,[X|U2],[I|Quyruk]) ,
**W = I**, U3 = Quyruk .
This code appends first two lists when I delete "W is X".
This code has unnecessary variables like "W is X" but they are about my question.
When I set any value to "W" between ":-" and ",append..." like "W is X" or "W = 3" or "W = 6" -- returns false.
Why can't I set any value to the W at that position in code but I CAN set "W = I" at the end of the code?
The query is append([1,2],[3],U). I want to get [2,1,3] at this code
at append([1,2,3],[4,5,6],U). I want to get [3,2,1,4,5,6].
append([1],[2,3],U). returns [1,2,3] , when I take the length of first list "1" (when first list only has one element) the code is perfect ; but when I take the length of first list >1 (when first list has more than one element) the code returns false.
In prolog, you can't assign variables, and then reassign them. Variables are unified and instantiated. Once instantiated, they cannot be re-instantiated inside of a clause. So if you have this inside of a clause:
W = X,
...
W = I,
Then first W is unified with X (=/2 is the unification operator). That means they either both now have the same value instantiated (if at least one was instantiated before), or their values will be forced to be identical instantiation later in the clause. When W = I is encountered later, then I must be unifiable with W or the clause will fail. If I has a specific value instantiated that is different from the instantiation of W (and, therefore, X), the clause will necessarily fail.
Let's see it happen (note I changed the name to my_append since Prolog rejects redefining the built-in predicate, append):
my_append([],U,U).
my_append([X|U1], U2, [W|U3]) :-
W = X,
my_append(U1, [X|U2], [I|Quyruk]),
write('I = '), write(I), write('; W = '), write(W), nl,
W = I,
U3 = Quyruk.
If we run:
?- my_append([1], [1,2], L).
I = 1; W = 1
L = [1,2,3]
yes
Life is good. Now let's try:
| ?- my_append([1,2], [3,4], L).
I = 2; W = 2 % This will be OK
I = 2; W = 1 % Uh oh... trouble
no
Prolog cannot unify 1 and 2, as I described above. They are two different values. So the predicate fails due to the W = I statement.
The solution is a little simpler than what you're attempting (although you are very close):
% Append empty to list gives the same list
my_append([], U, U).
% Append of [X|U1] and U2 is just append U1 and [X|U2]
% Or, thought of another way, you are moving elements of the first list
% over to the head of the second one at a time
my_append([X|U1], U2, U3) :-
my_append(U1, [X|U2], U3).
| ?- my_append([1,2,3],[4,5,6],L).
L = [3,2,1,4,5,6]
yes
The essence of this was in your code. Those other variables were just getting in the way (as C.B. pointed out). :)
The is operator is specifically used to compare or unify integers. W = I Is attempting to unify W with I (regardless of type). When you Unify W with X (assuming X is an integer), you have already unified W, and if X\=I (doesn't unify) you will return false.
In your example, W unifies with 1, but then you try to unify it with 2.
You have a lot of unnecessary variables, here is a very simple implementation of append:
append([],XS,XS).
append([X|XS],YS,[X|ZS]):- append(XS,YS,ZS).
To understand whats going wrong with your code, lets walk through it
append([],U,U).
append([X|U1],U2,[W|U3]) :- W is X , append(U1,[X|U2],[I|Quyruk]) , W = I, U3 = Quyruk .
?-append([1,2,3],[4,5,6],U).
I will use X1,X2,... to differentiate between different bindings.
In the first call, X unifies with 1, U1 unifies with [2,3] and U2 unifies with [4,5,6]. W and U3 are not yet bound before going into the horn clause.
W is X unifies W with 1.
append(U1,[X|U2],[I|Quyruk]) is calling append([2,3],[1,4,5,6],[I|Quyruk]). Already you should see that your recursion isn't working correctly.

Prolog calls wrong rule. Does not backtrack correctly

Whats up?
I'm having some really weird problems with Prolog.
A recursive rule to replace an element in a list at a given index isn't always working.
My rule looks like this:
% Base rule - Stops when index is 1 and replaces the head with the element.
replaceAtIndex(1, _element, [_|_tail], [_element|_tail]).
% Recursive rule - Enter recursion for tail as long as index is larger than 1.
replaceAtIndex(_index, _element, [_head|_tail], [_head|_new_tail]):-
_index > 1,
_new_index is _index - 1,
replaceAtIndex(_new_index, _element, _tail, _new_tail).
When I use the debugger from within my program I see its always calling the second rule no matter what the index is, but when I execute the exact same command outside my program it works perfectly well. It reaches index 1 but calls the second rule, and does NOT backtrack and attempt the first rule and fails all the way back up...
The rule calling the replaceAtIndex looks like this:
level_replace_block_value(_x, _y, _value):-
current_level(_level_number, _width, _height, _blocks, _drawX, _drawY),
coordinates_to_index(_x, _y, _index),
_index_in_list is _index + 1, % the replaceAtIndex is not 0 terminated
replaceAtIndex(_index_in_list, _value, _blocks, _new_blocks),
retractall(current_level(_,_,_,_,_,_)),
assert(current_level(_level_number, _width, _height, _new_blocks, _drawX, _drawY),
graphics_update_block_value(_x, _y).
When I'm debugging its calling with index being 111.
When I'm replacing the _index_in_list with a constant 111 it works.
Anyone might have a clue why that happens?
Preserve logical-purity by using the builtin predicates same_length/2, length/2 and append/3!
replace_at(I,X,Xs0,Xs2) :-
same_length(Xs0,Xs2),
append(Prefix,[_|Xs1],Xs0),
length([_|Prefix],I),
append(Prefix,[X|Xs1],Xs2).
First, let's run the sample query that #magus used in a previous answer to this question:
?- replace_at(3,0,[1,2,3,4,5,6],Xs).
Xs = [1,2,0,4,5,6] ;
false.
Does it work when the list items are instantiated later?
?- replace_at(3,0,[A,B,C,D,E,F],Xs), A=1,B=2,C=3,D=4,E=5,F=6.
A = 1, B = 2, C = 3, D = 4, E = 5, F = 6, Xs = [1,2,0,4,5,6] ;
false.
Yes! What if the index isn't a concrete integer, but an unbound logical variable? Does that work?
?- replace_at(I,x,[_,_,_,_,_],Ys).
I = 1, Ys = [ x,_B,_C,_D,_E] ;
I = 2, Ys = [_A, x,_C,_D,_E] ;
I = 3, Ys = [_A,_B, x,_D,_E] ;
I = 4, Ys = [_A,_B,_C, x,_E] ;
I = 5, Ys = [_A,_B,_C,_D, x] ;
false.
It does! With monotone code, we get logically sound answers even with very general queries.
I suspect you misunderstand the direction in which backtracking will take place.
The first "base" rule will be tried first for any call to replaceAtIndex/4. If it fails, due to non-unifiability of the call with the "head" of the first rule, then the Prolog engine backtracks to the second rule. [Unification failure might result either from the first argument (index) differing from 1 or from the third argument not being a nonempty list.]
Backtracking never goes in the other direction. If the second rule is tried and fails, the call fails.
Of course things are complicated by the recursive definition. The success of applying the second rule entails a new call to replaceAtIndex/4, which as far as the Prolog engine is concerned must begin attempting to satisfy that goal by starting back at the first rule.
I'd suggest adding a cut to the first rule, since by construction the second rule will never succeed if the first rule does. But this is just an efficiency issue... why leave a choicepoint open that will never produce any further solutions?
replaceAtIndex(1, _element, [_|_tail], [_element|_tail]) :- !.
Added: I confirmed that your code works in Amzi! Prolog with a call like this:
?- replaceAtIndex(3, 0, [1,2,3,4,5,6], L).
L = [1, 2, 0, 4, 5, 6] ;
no
?-
But of course you also see success when the code is called in standalone/interpreted mode.
So I have to suspect the "index" argument being passed in is not an integer but rather a floating point number. Integer 1 will not unify with floating point 1.0, even if they are mathematically equal.
You can use the predicate is_integer/1 to test for this in Amzi! Prolog. The function integer(X) can be used to convert real 1.0 to an integer 1 by truncating the (nonexistent) fractional part.
Try _index_in_list set to 1. Wouldn't the first rule get called then?
Sure the reason why the second rule is getting called if your _index_in_list is 111 is because 111 is greater than 1 ? The first rule only deals with 1 - as the first parameter says.
When I'm replacing the _index_in_list with a constant 111 it
works.
What? You mean the first rule gets called? How can that be, the first param is 1.
replaceAtIndex(I, Value, List, Result) :-
RI is I-1,
findall(Before, (nth0(B, List, Before), B < RI), Before),
findall(After, (nth0(A, List, After), A > RI), After),
append([Before, [Value], After], Result).
?- replaceAtIndex(3,0,[1,2,3,4,5,6], L).
L = [1, 2, 0, 4, 5, 6].

Resources