I working in prolog for first time.
I am trying to convert operations in text.
Such as,
THREE + THREE = SIX
should return true.
I tried this.
I am getting error on last line and when I try add(ONE,ONE,TWO) it returns false instead of true.
numericValue(ONE, 1).
numericValue(TWO, 2).
numericValue(THREE, 3).
numericValue(FOUR, 4).
numericValue(FIVE, 5).
numericValue(SIX, 6).
numericValue(SEVEN, 7).
numericValue(EIGHT, 8).
numericValue(ZERO, 0).
numericValue(NINE, 9).
add(num1,num2,num3):-
numericValue(num1,a),
numericValue(num2,b),
numericValue(num3,c),
(c =:= a+b -> true ; false).
istBiggerThen(XinEng,YinEng) :-
numericValue(XinEng, X),
numericValue(YinEng, Y),
( X < Y -> true ; false).
A + B = C :- add(A,B,C).
Error on last line is
ERROR: /home/name/prolog_examples/crypt.pl:24:
No permission to modify static procedure `(=)/2'
literals (lower-case) vs. Variabls (upper-case):
as #lurker pointed out, you have your atoms and variables mixed up. So your facts should look something like this:
text_to_number(one, 1).
text_to_number(two, 2).
text_to_number(three, 3).
%% etc...
while your rules will need to use variables, like so:
add(A_Text, B_Text, C_Text) :-
text_to_number(A_Text, A_Num),
text_to_number(B_Text, B_Num),
C_Num is A_Num + B_Num,
text_to_number(C_Text, C_Num).
bigger_than(A_Text, B_Text) :-
text_to_number(A_Text, A_Num),
text_to_number(B_Text, B_Num),
A_Num > B_Num.
The reason reason why add(ONE, ONE, TWO) turns out false is because your original rule for add/3 only defines relationships between the atoms num1, num2, num3, a, b, c. When you query add(ONE, ONE, TWO) Prolog tries to unify the variables with the atoms in the head of your rule, which is add(num1, num2, num3). Because you have ONE as the first and second argument of your query, this unification is impossible, since ONE = ONE but num1 \= num2. As there are no further rules or facts for add/3, the query simply returns false.
Using the pattern (|Condition| -> true ; false):
Statements in the body of a clause (i.e., to the right of the :- operator) is evaluated to be either true or false, so you will almost never need to use the pattern (|Condition| -> true ; false). E.g. C_Num is A_Num + B_Num is true iff C_Num can be unified with the sum of A_Num and B_Num, or else it is false, in which case Prolog will start back tracking.
Using =:=/2 vs. is/2:
=:=/2 checks for the equality of its first argument with the value of its second argument, which can be an arithmetical expression that can be evaluated using is/2. Query ?- X =:= 2 + 2 and you'll get an instantiation error, because =:=/2 cannot compare a free variable to a mathematical expression. is/2, on the other hand, unifies the variable on the left with the value of the expression on the right: ?- X is 2 + 2. X = 4.
Your use of =:=/2 would work (provided you straightened out the variable-atom thing), but your rule describes an inefficient and roundabout solution for the following reason: since numericValue(Num3,C) precedes evaluation of the arithmetic, Prolog will first unify numericValue(Num3,C) with the first fitting fact, viz. numericValue(one, 1) then test if 1 =:= A + B. When this fails, Prolog will unify with the next fact numericValue(two, 2) then test if 2 =:= A + B, then the next... until it finally happens upon the right value. Compare with my suggested rule: the numeric values A_Num and B_Num are summed with C_Num is A_Num + B_Num, unifying C_Num with the sum. Then Prolog unifies text_to_number(C_Text, C_Num) with the single fitting fact that has the appropriate value for C_Num.
Defining operators:
When a term appears on the right of a :-, or on the top level of the program, is being defined. However, you cannot simply redefine predicates (it can be done, but requires some bookkeeping and special declarations. Cf., dynamic/1). Moreover, you wouldn't want to redefine core terms like +/2 and =/2. But you can define your own predicates with relative ease. In fact, going crazy with predicate definitions is one of my favorite idle things to do with Prolog (though I've read cautions against using unnecessary operators in practice, since it makes your code recondite).
Operators are declared using op/3 in a directive. It has the signature op(+Precedence, +Type, :Name) (Cf., the SWI-Prolog documentation):
:- op(200, xfx, user:(++)).
:- op(300, yfx, user:(=::=)).
A ++ B =::= C :- add(A, B, C).
In action:
?- one ++ two =::= X.
X = three.
Related
I'm learning prolog using SWI Prolog and the tutorial here. I find that if I express the collatz conjecture exactly like they do in the video, it works as long as I replace #= with is which I'm guessing is a swipl vs scryer-prolog difference. But if I tweak the definition at all it seems to break, either with an error or incorrect conclusions. Why do my alternative definitions fail? Code:
use_module(library(clpfd)).
%% Does work, collatz_next(A, 1) gives A=2
collatz_next(N0, N) :-
N0 is 2*N.
collatz_next(N0, N) :-
N0 is 2*_ + 1,
N is 3*N0 + 1.
%% Doesn't work, collatz_next(A, 1) gives false
%% collatz_next(N0, N) :- ((N0 mod 2) is 0),((N0 / 2) is N).
%% collatz_next(N0, N) :- ((N0 mod 2) is 1),((N0 * 3 + 1) is N).
%% Doesn't work, collatz_next(A, 1) gives false
%% collatz_next(N0, N) :- ((N0 mod 2) is 0),(N0 is 2*N).
%% collatz_next(N0, N) :- ((N0 mod 2) is 1),((N0 * 3 + 1) is N).
%% Doesn't work
%% "Arguments are not sufficiently instantiated"
%% collatz_next(N0, N) :-
%% N0 / 2 is N.
%% collatz_next(N0, N) :-
%% N0 is 2*_ + 1,
%% N is 3*N0 + 1.
As brebs already wrote in the comments, you have to include the line :- use_module(library(clpfd)). if you are using SWI-Prolog. However, if you are using Scryer Prolog the library is called clpz, so you have to include the line :- use_module(library(clpz)).. The predicate collatz_next/2 (from the linked video) works with both Prologs as described in the video if you use the respective libraries (I tested it with Scryer Prolog version 0.9.0. and SWI-Prolog version 8.4.2, both 64bit on a linux machine). Since it has not been mentioned in the comments yet, I would also refer you to the description of CLP(FD) and CLP(Z) in The Power of Prolog.
Now to your question about the failing alternatives. The built-in is/2 is true if the expression on the right hand side evaluates to the number on the left hand side. If the left hand side is an uninstantiated variable, the variable contains the value of the expression on the right hand side after the call of the goal. In order for this to succeed all variables in the expression on the right hand side need to be instatiated. Consider the following examples:
?- 3 is 2+1.
true.
?- X is 2+1.
X = 3.
?- 3 is X+1.
ERROR: Arguments are not sufficiently instantiated
...
?- 3 is 2+X.
ERROR: Arguments are not sufficiently instantiated
...
Furthermore if the left hand side is instantiated with a float rather than with an integer is/2 will fail:
?- 3.0 is 2+1.
false.
Now that we covered some basics let's take a look at your first predicate:
%% Does work, collatz_next(A, 1) gives A=2
collatz_next(N0, N) :-
N0 is 2*N.
collatz_next(N0, N) :-
N0 is 2*_ + 1,
N is 3*N0 + 1.
Let's observe that, while your given example produces a correct answer, after pressing the ;-key it throws an instantiation error:
?- collatz_next(A, 1).
A = 2 ;
ERROR: Arguments are not sufficiently instantiated
...
What's going on here? You're posting the query collatz_next(A, 1)., hence the variable N0 in the head of your predicate is unified with the variable A and the variable N is unified with 1. With these unifications the only goal in the first rule, N0 is 2*N, now becomes A is 2*1. That yields the answer A = 2. Prolog now tries the second rule of collatz_next/2, where the first goal, N0 is 2*_ + 1 now becomes A is 2*_ + 1. Here the right hand side still contains a variable (_), hence the expression is not sufficiently instatiated to be evaluated thus Prolog throws an instantiation error.
Now let's try to use the predicate the other way around. As you can see in the Youtube-video, if N0=5 then the expected answer is N=16. However, if you query that with your predicate you get no answer and an instantiation error:
?- collatz_next(5, N).
ERROR: Arguments are not sufficiently instantiated
...
Looking at your definition of collatz_next/2 we can observe that the variable N0 in the head of the rule is unified with 5, while the second argument N remains uninstantiated. The single goal in the first rule, N0 is 2*N, becomes 5 is 2*N hence the instantiation error due to the variable on the right hand side.
Note, that the video is also showing that the most general query :- collatz_next(N0,N). is still producing answers due to the use of CLP(FD)/CLP(Z), while your version, using is/2, is again producing an instantiation error.
The next two versions of collatz_next/2 you posted (the ones with the comment %% Doesn't work, collatz_next(A, 1) gives false) fail with the first goal in the rules. Since you query :- collatz_next(A, 1). the variable N0 in the head of the rules is unified with the variable A, so the first goal in all four rules becomes ((A mod 2) is 0) and ((A mod 2) is 1) respectively. If you try these goals as queries the answer is false:
?- ((A mod 2) is 0).
false.
?- ((A mod 2) is 1).
false.
And since the first goal of the rule fails, Prolog won't even try the second goal because once you have a false in a (chain of) conjunction(s) it cannot yield true. This is the case for both rules of both predicates hence the answer to your queries is false. If you, on the other hand, try to exchange the left hand sides of is/2 with the right hand sides you will get an instantiation error:
?- (0 is (A mod 2)).
ERROR: Arguments are not sufficiently instantiated
...
?- (1 is (A mod 2)).
ERROR: Arguments are not sufficiently instantiated
...
Maybe think about it this way: What can you expect to happen if you try to evaluate an uninstantiated variable modulo an actual number? One reasonable expectation would be to get some sort of feedback stating that it can't be done.
Another reasonable point of view would be to expect Prolog to propagate the posted goal as a constraint until it can (hopefully) be solved at a later time. This is basically what CLP(FD)/CLP(Z) does (see also the section on Constraint propagation in CLP(FD) and CLP(Z) in The Power of Prolog. Just try the above queries with (#=)/2:
?- ((A mod 2) #= 0).
A mod 2#=0. % residual goal
?- ((A mod 2) #= 1).
A mod 2#=1. % residual goal
?- (0 #= (A mod 2)).
A mod 2#=0. % residual goal
?- (1 #= (A mod 2)).
A mod 2#=1. % residual goal
As you can see, the posted constraints are now propagated and appear as residual goals at the end of the deduction since in these cases, with the queries just consisting of those single goals, they cannot be further resolved.
The last version you posted (marked with the comment %% Doesn't work) has the left hand side and the right hand side of is/2 the wrong way around in the single goal of the first rule, as pointed out by TessellatingHeckler in the comments. But even if you exchange them you will get an instantiation error unless the variable N0 is instantiated. But even then you will still get an instantiation error once Prolog tries the second rule because its first goal N0 is 2*_ + 1 contains a variable _ that is always uninstantiated:
?- N0 is 2*_ + 1.
ERROR: Arguments are not sufficiently instantiated
...
?- 1 is 2*_ + 1.
ERROR: Arguments are not sufficiently instantiated
...
The bottom line is: If you want to use low-level predicates like is/2 you have to be aware of their limitations. If you want to declaratively reason over integers you can't easily get around CLP(FD)/CLP(Z). And if you decide to use a predicate like collatz_next/2 as presented in the video, you can't exchange CLP(FD)/CLP(Z)-constraints one-to-one for low-level predicates like is/2 and expect the same results.
Can anybody explain the following code? I know it returns true if X is left of Y but I do not understand the stuff with the pipe, underscore and R. Does it mean all other elements of the array except X and Y?
left(X,Y,[X,Y|_]).
left(X,Y,[_|R]) :- left(X,Y,R).
If you are ever unsure about what a term "actually" denotes, you can use write_canonical/1 to obtain its canonical representation.
For example:
| ?- write_canonical([X,Y|_]).
'.'(_16,'.'(_17,_18))
and also:
| ?- write_canonical([a,b|c]).
'.'(a,'.'(b,c))
and in particular:
| ?- write_canonical([a|b]).
'.'(a,b)
This shows you that [a|b] is the term '.'(a,b), i.e., a term with functor . and two arguments.
To reinforce this point:
| ?- [a|b] == '.'(a,b).
yes
#mat answered the original question posted quite precisely and completely. However, it seems you have a bigger question, asked in the comment, about "What does the predicate definition mean?"
Your predicate, left(X, Y, L), defines a relation between two values, X and Y, and a list, L. This predicate is true (a query succeeds) if X is immediately left of Y in the list L.
There are two ways this can be true. One is that the first two elements in the list are X and Y. Thus, your first clause reads:
left(X, Y, [X,Y|_]).
This says that X is immediately left of Y in the list [X,Y|_]. Note that we do not care what the tail of the list is, as it's irrelevant in this case, so we use _. You could use R here (or any other variable name) and write it as left(X, Y, [X,Y|R]). and it would function properly. However, you would get a singleton variable warning because you used R only once without any other references to it. The warning appears since, in some cases, this might mean you have done this by mistake. Also note that [X,Y|_] is a list of at least two elements, so you can't just leave out _ and write [X,Y] which is a list of exactly two elements.
The above clause is not the only case for X to be immediately left of Y in the list. What if they are not the first two elements in the list? You can include another rule which says that X is immediately left of Y in a list if X is immediately left of Y in the tail of the list. This, along with the base case above, will cover all the possibilities and gives a complete recursive definition of left/3:
left(X, Y, [_|R]) :- left(X, Y, R).
Here, the list is [_|R] and the tail of the list is R.
This is about the pattern matching and about the execution mechanism of Prolog, which is built around the pattern matching.
Consider this:
1 ?- [user].
|: prove(T):- T = left(X,Y,[X,Y|_]).
|: prove(T):- T = left(X,Y,[_|R]), prove( left(X,Y,R) ).
|:
|: ^Z
true.
Here prove/1 emulates the Prolog workings proving a query T about your left/3 predicate.
A query is proven by matching it against a head of a rule, and proving that rule's body under the resulting substitution.
An empty body is considered proven right away, naturally.
prove(T):- T = left(X,Y,[X,Y|_]). encodes, "match the first rule's head. There's no body, so if the matching has succeeded, we're done."
prove(T):- T = left(X,Y,[_|R]), prove( left(X,Y,R) ). encodes, "match the second rule's head, and if successful, prove its body under the resulting substitution (which is implicit)".
Prolog's unification, =, performs the pattern matching whilst instantiating any logical variables found inside the terms being matched, according to what's being matched.
Thus we observe,
2 ?- prove( left( a,b,[x,a,b,c])).
true ;
false.
3 ?- prove( left( a,b,[x,a,j,b,c])).
false.
4 ?- prove( left( a,b,[x,a,b,a,b,c])).
true ;
true ;
false.
5 ?- prove( left( a,B,[x,a,b,a,b,c])).
B = b ;
B = b ;
false.
6 ?- prove( left( b,C,[x,a,b,a,b,c])).
C = a ;
C = c ;
false.
The ; is the key that we press to request the next solution from Prolog (while the Prolog pauses, awaiting our command).
Something like this:
decr(X, X) :-
X is X-1.
I want to use it for decrement a number in the parent rule , if this number equal 0 for example, the parent rule return false.
Prolog is declarative: one of the properties of a declarative language is that once you set a variable, you cannot give it another value anymore. In Prolog backtracking can of course "unground" a variable and furthermore you can assign a partially grounded expression to a variable (like X=f(1,_)), but when you move deeper into the call stack, each expression can only be grounded further.
As a result: you have to use another variable. Like:
decr(X,NX) :-
NX is X-1.
This is also logical: here you defined decr(X,X) and since the argument of predicates in Prolog have no input/output direction, it is unclear whether you want to call it like decr(4,3), decr(X,3), decr(4,X) or decr(X,Y). So how can Prolog "know" that your second X is supposed to be the "new X"? It is thus a "fundamental property" of Prolog you cannot use X, call a predicate, and all of a sudden X has a different value (it can however - as said before - be grounded further, but an integer cannot be grounded further).
The reason why it will always error or fail is because, either X is not instantiated: (like decr(_,_)) in which case Prolog cannot calculate X is _-1, or you have given one of the argument a number (decr(X,3), decr(4,X) or decr(3,3)), but in that case you ask that both operands can unify (since they are both X) and are off by one at the same time, which is a contradiction.
As already mentioned, you can't reassign variables in Prolog, but the closest thing available out-of-box to what you apparently want is succ/2 predicate:
?- succ(1, X).
X = 2.
?- succ(X, 5).
X = 4.
The next closest is probably plus/3:
?- plus(1, 2, X).
X = 3.
?- plus(1, X, 3).
X = 2.
?- plus(X, 2, 3).
X = 1.
I'm new to Prolog and I'm trying to write a piece of code that calculates factorial of a number.
This code works fine:
fact(0,1).
fact(N, R) :- N > 0, N1 is N - 1, fact(N1, R1), R is R1 * N.
But this one doesn't:
fact(0, 1).
fact(N, R) :- N > 0, fact(N - 1, R1), R is R1 * N.
Can someone please explain?
The issue is that prolog primarily uses unification to do computation. To get it to do arithmetic operations you need to tell it to do so explicitly using the is operator.
So, in your first program you explicitly tell it to perform subtraction with the clause N1 is N - 1, so that works as expected.
But in your second program you are not asking for arithmetic computation, but unification, when you wrote fact(N - 1, R1).
If I had the fact fact(5 - 1, foo). defined, then I could query for ?- fact(N - 1, Y), write([N, Y]). and prolog would happily unify N with 5 and Y with foo. This query would output [5, foo].
So, to go one step further, if I had the fact fact(foo - bar). then the query ?- fact(X - Y), write([X, Y]). would happily unify and return [foo, bar]. The - doesn't denote subtraction - it's part of the structure of the fact being represented.
When passing around arithmetic expressions (instead of numbers), you need to evaluate expressions at certain times.
Arithmetic operators like (>)/2 automatically do that, so the goal 1 > (0+0) succeeds, just like 1 > 0 does.
Implicit unification (in clause heads) and explicit unification with (=)/2 goals expresses equality of arbitrary Prolog terms, not just arithmetic expressions. So the goal 0 = 0 succeeds, but 0 = (1-1) fails.
With arithmetic equality (=:=)/2, both 0 =:= 0 and 0 =:= (1-1) succeed.
In your second definition of fact/2, you could make the first clause more general by writing fact(N,1) :- N =:= 0. instead of fact(0,1).. As an added bonus, you could then run queries like ?- fact(5+5,F). :)
I need some help here with Prolog.
So I have this function between that evaluates if an element is between other two.
What I need now is a function that evaluates if a member is not between other two, even if it is the same as one of them.
I tried it :
notBetween(X,Y,Z,List):-right(X,Y,List),right(Z,Y,List). // right means Z is right to Y and left the same for the left
notBetween(X,Y,Z,List):-left(X,Y,List),left(Z,Y,List).
notBetween(X,Y,Z,List):-Y is Z;Y is X.
I am starting with Prolog so maybe it is not even close to work, so I would appreciate some help!
When it come to negation, Prolog behaviour must be handled more carefully, because negation is 'embedded' in the proof engine (see SLD resolution to know a little more about abstract Prolog). In your case, you are listing 3 alternatives, then if one will not be true, Prolog will try the next. It's the opposite of what you need.
There is an operator (\+)/2, read not. The name has been chosen 'on purpose' different than not, to remember us that it's a bit different from the not we use so easily during speaking.
But in this case it will do the trick:
notBeetwen(X,Y,Z,List) :- \+ between(X,Y,Z,List).
Of course, to a Prolog programmer, will be clearer the direct use of \+, instead of a predicate that 'hides' it - and requires inspection.
A possibile definition of between/4 with basic lists builtins
between(X,Y,Z,List) :- append(_, [X,Y,Z|_], List) ; append(_, [Z,Y,X|_], List).
EDIT: a simpler, constructive definition (minimal?) could be:
notBetween(X,Y,Z, List) :-
nth1(A, List, X),
nth1(B, List, Y),
nth1(C, List, Z),
( B < A, B < C ; B > A, B > C ), !.
EDIT: (==)/2 works with lists, without side effects (it doesn't instance variables). Example
1 ?- [1,2,3] == [1,2,3].
true.
2 ?- [1,2,X] == [1,2,X].
true.
3 ?- [1,2,Y] == [1,2,X].
false.